Skip to content

Codebase readability & restructuring

Status: Open — active program (deep audit May 2026)

Make AI-generated code verifiable and maintainable. The codebase has grown to ~91K lines of production Rust (116 files in src/) with significant AI-assisted development. The core problems are:

  1. Files have outgrown their module boundaries — 21 files exceed 1000 lines; the largest is 7575L. 18 additional files over 800L are not yet tracked for splitting.
  2. Pervasive copy-paste duplication — 231 Style::default() chains across 21 files, 82 identical Dockerfile FROM literals, 123 inline manifest filename strings, 10 independent mount helper definitions, 4 byte-for-byte-identical config_with_agents test functions, 7+ agent match-arm dispatch blocks that all need updating when a new agent is added.
  3. Mega-functions — 25 functions carry #[allow(clippy::too_many_lines)] suppressions; the worst (fn run in app/mod.rs) is 1141 lines. These make PR review nearly impossible.
  4. Weak module contracts — 51 of 116 files (44%) still lack //! orientation docs; no behavioral specs exist; no snapshot tests exist.
  5. DRY violations in constants"jackin.role.toml" appears 123 times, "Dockerfile" 230 times, "FROM projectjackin/construct:trixie\n" 82 times — all should be shared constants.
  • Layered config resolution — global / workspace / workspace×role env resolution is well-structured in config/roles.rs
  • Instance identity systeminstance/naming.rs provides centralized container name generation
  • Migration frameworkconfig/migrations.rs and manifest/migrations.rs provide versioned schema upgrades with fixture-tested chains
  • Isolation boundaryisolation/materialize.rsisolation/finalize.rs have clean complementary responsibilities
  • Wildcard imports — zero wildcard use in production code; all 91 wildcard imports are properly scoped to #[cfg(test)] modules

Weakest parts (highest duplication / entropy risk)

Section titled “Weakest parts (highest duplication / entropy risk)”
  • TUI render layerconsole/manager/render/ and all widget files: 231 Style::default().fg() calls, 347 Span::styled() calls, 19 Block::default() chains, inline color constants duplicated across 10+ files instead of using the centralized palette in console/widgets/mod.rs
  • Auth provisioninginstance/auth.rs contains 5 near-identical provision functions; 7+ agent match-arm dispatch blocks across the codebase mean adding a new agent requires touching 7+ files
  • String literal duplication"FROM projectjackin/construct:trixie\n" (82 occurrences in 8 files), "jackin.role.toml" (123 in 12 files), "Dockerfile" (230 in 15 files) — all inline instead of shared constants
  • Test infrastructure — 11 separate mock/fake struct definitions; 10 independent mount helper functions in 7 files; 4 byte-for-byte-identical config_with_agents test helpers; 20 inline ResolvedWorkspace constructions
  • Mega-functionsfn run (1141L), fn load_role_with (695L), fn entrypoint_dispatches_on_jackin_agent (446L) are the top 3; 25 total functions have too_many_lines suppressions
  • Agent-generated entropy accelerating: each new agent runtime duplicates auth provision patterns, TUI tab handling, and match-arm dispatch across 7+ files
  • The “clean console/runtime boundary” claim was never enforced and now has 2 production dependencies — the window for a clean Cargo workspace split is narrowing
  • No snapshot tests exist, so Phase 2 file splits risk silent render regressions
  • console/ is 42% of the entire codebase (38,499L across 49 files) but has the best //! coverage (90%); instance/, isolation/, manifest/, and tui/ all have 0% doc coverage
ModuleFilesLines//! coverageBiggest risk
console/4938,49990%Render duplication; deep nesting (5-6 levels)
runtime/1111,83118%launch.rs at 7575L; attach.rs duplicates DinD logic
config/77,42114%editor.rs at 2260L; 51 JackinPaths::for_tests() calls
isolation/65,3750%materialize.rs at 2392L; deep nesting
workspace/74,59129%token_setup.rs at 1610L
instance/44,3880%auth.rs at 2607L; 5 copy-pasted provision functions
app/24,2330%mod.rs at 2767L with 1141L fn run
manifest/32,2590%validate.rs at 1222L
cli/72,46414%workspace.rs at 861L
tui/41,6820%animation.rs has 12+ magic-number millisecond values
agent/12890%Small but undocumented

MSRV & toolchain pin — rust-toolchain.toml enforced in CI, MSRV floor verified. Resolved.

Phase 1 — Documentation & setup (low risk, no structural code changes)

Section titled “Phase 1 — Documentation & setup (low risk, no structural code changes)”

These items require no structural code changes and can be done in any order within the phase (with the dependency notes below):

ItemPurposeDepends on
Module contractsWrite //! docs for priority files (51 of 116 missing)
Behavioral spec: runtime/launch.rsVerified invariants for the jackin load critical path (7575L)Module contracts first
Behavioral spec: op_pickerInvariants for the 1Password picker state machine (2331L)
Per-directory READMEAI-native orientation files + per-crate AGENTS.md
Developer Reference setupjackin.tailrocks.com/internal/ Starlight section
PROJECT_STRUCTURE.md refreshCompleted; root map now delegates detailed source navigation to Codebase Map
CI gate: PROJECT_STRUCTURE.mdFail PRs that add modules without updating the mapProject structure update first
pub(crate) visibility passTighten over-wide visibilities after clarifying the library surface
Architecture Decision RecordsADRs for single-crate, toolchain, ratatui decisionsDeveloper Reference setup
Snapshot tests for TUIRegression net before Phase 2 file splits
Agent workflow: cc-sddDefine a repo-committed spec workflowDeveloper Reference setup
Publish CONTRIBUTING + TESTINGMirror contributor docs into the browsable Starlight sectionDeveloper Reference setup

Before splitting files in Phase 2, reduce the duplication within them. This phase directly addresses the copy-paste patterns that make PR review hard.

1. Shared string constants (highest ROI — touches entire codebase)

Section titled “1. Shared string constants (highest ROI — touches entire codebase)”
ConstantCurrent duplicationOccurrencesFiles
const BASE_DOCKERFILE_FROM: &str"FROM projectjackin/construct:trixie\n" inline82 in 8 fileslaunch.rs, derived_image.rs, repo_cache.rs, repo.rs, instance/mod.rs, editor.rs, repo_contract.rs, auth.rs
const MANIFEST_FILENAME: &str"jackin.role.toml" inline123 in 12 fileslaunch.rs, validate.rs, mod.rs, repo.rs, repo_cache.rs, derived_image.rs, migrations.rs, instance/mod.rs, editor.rs, context.rs, auth.rs, validate.rs
const DOCKERFILE_NAME: &str"Dockerfile" inline230 in 15 fileslaunch.rs, validate.rs, mod.rs, repo.rs, repo_cache.rs, derived_image.rs, repo_contract.rs, image.rs, instance/mod.rs, migrations.rs, context.rs, editor.rs, auth.rs, confirm.rs, role.rs
ExtractionCurrent duplicationFiles affectedImpact
fn titled_block(title, focused) -> Block18 Block::default().borders(ALL) + 15 border_style chains + 13 title constructions (78 total sites)render/editor.rs, render/list.rs, render/global_mounts.rsCollapses 78 boilerplate chains
Named style constants (BOLD_WHITE, DIM, GREEN, BORDER, DANGER)231 Style::default().fg(...) chains across 21 files; Style::default().fg(WHITE).add_modifier(BOLD) alone appears 26 timesAll render files + all widget files + input/save.rsEliminates 231 inline style constructions
Centralized color palette importInline Color::Rgb(...) values duplicated in input/save.rs, scope_picker.rs, save_discard.rs, mount_dst_choice.rs, source_picker.rs, file_browser/render.rs instead of importing from console/widgets/mod.rs6+ filesRemoves ~20 inline magic color values
fn app_layout(area) -> Rc<[Rect]> for header/body/footer4 identical Layout::default() splits with [Length(3), Min(..), Length(2)]render/mod.rs, render/global_mounts.rsRemoves 4 duplicate layout constructions
Deduplicate breadcrumb logicpush_op_breadcrumb_spans() at render/editor.rs:1427 is fully duplicated inline at lines 1058–1091render/editor.rsOne call replaces ~30 duplicated lines
Extract config_with_agents to shared test utility4 copies of the same function (3 are byte-for-byte identical in render/editor.rs); 1 variant in input/editor.rsrender/editor.rs, input/editor.rs4 functions → 1 shared helper

3. Auth provisioning & agent dispatch deduplication

Section titled “3. Auth provisioning & agent dispatch deduplication”
ExtractionCurrent duplicationFiles affected
Generic fn provision_file_credential(target, host_path, mode)The Sync arm (read host file → write to role-state → HostMissing on NotFound) is copy-pasted across Codex, Amp, and GitHub provisioners in src/instance/auth.rs. The wipe-then-return for ApiKey/Ignore is identical across 4 agents.src/instance/auth.rs (2607L)
AgentRuntimeState::model() accessor3 identical match-body methods (claude_model(), codex_model(), kimi_model()) in src/instance/mod.rssrc/instance/mod.rs
Agent match-arm macro or trait dispatch7+ sites with Agent::Claude => ..., Agent::Codex => ..., Agent::Amp => ... match arms (config/roles.rs has three identical blocks, instance/mod.rs has 2, launch.rs has 4, auth_kind.rs 1, agent_choice/mod.rs 1, derived_image.rs 1). Adding a new agent requires touching all 7.7 files across config, runtime, instance, console, derived_image
ExtractionCurrent duplicationFiles affected
DockerResources::from_container_name(name) struct with dind, network, certs_volume fields44+ inline format!("{name}-dind") / format!("{name}-net") derivations across 5 fileslaunch.rs, attach.rs, cleanup.rs, app/mod.rs, app/context.rs
fn run_dind_sidecar(runner, name, network, role_label, certs)Identical DinD sidecar docker run arg list at launch.rs:777-799 and attach.rs:472-498runtime/launch.rs, runtime/attach.rs
fn resolve_mode_with_trace() returning both mode and layer tracebuild_mode_resolution() in launch.rs:2977-3011 duplicates the 3-layer × 4-agent match (12 arms) from config/roles.rs:22-56 solely to capture the resolution traceruntime/launch.rs, config/roles.rs
ExtractionCurrent duplicationFiles affected
Promote FakeRunner to pub or move to src/test_support.rs3 independent FakeRunner definitions; tests/per_mount_isolation_e2e.rs has its own ScriptedRunner4 test files
fn seed_minimal_role_repo(paths, selector, manifest_toml)45+ copy-pasted seeding blocks across 10 files; uses the 82-occurrence FROM literal and 150+ version strings10+ test files
fn test_workspace(repo_dir) -> ResolvedWorkspace20 inline ResolvedWorkspace { ... } constructions across 5 files5 test files
fn simple_mount(src, dst, iso) -> MountConfig10 local fn mount() / fn worktree_mount() / fn clone_mount() / fn shared_mount() helpers across 7 files, each constructing a MountConfig with slight variations7 test files
Consolidate fake_runner_with_running2 near-identical helpers in app/context.rs and input/save.rs with a subtle trailing-newline format difference2 files
Consolidate render_to_dump test helpers3 definitions in render/editor.rs (different test modules, different signatures)1 file (3 modules)
AreaFileValuesAction
Animation timingtui/animation.rs12+ inline Duration::from_millis(...) values (80ms, 200ms, 300ms, 400ms, 500ms, 600ms, 800ms, 1500ms)Collect into named constants at top of file
Buffer sizesdocker.rs, host_claude.rs8192, 4096Named constants
Terminal defaultshost_claude.rs120 cols, 24 rowsNamed constants
DNS label limitinstance/naming.rs63 (DNS label max)Already has some constants; add the remaining

Phase 2 — File splits (confirmation required)

Section titled “Phase 2 — File splits (confirmation required)”

Split the largest files. Snapshot tests (Phase 1) and DRY extractions (Phase 1.5) must land first.

The original Phase 2 listed 4 files. The deep audit found 31 files exceed 800 lines, with 21 files exceeding 1000 lines.

Tier A — files over 2000 lines (13 files, highest priority)

Section titled “Tier A — files over 2000 lines (13 files, highest priority)”
FileLOCKey riskMega-functions inside
src/runtime/launch.rs7575Hardest file in the codebase. fn load_role_with is 695L.load_role_with (695L), launch_role_runtime (374L), resolve_restore_candidate (125L)
src/console/manager/input/editor.rs395561-arm match on modal, 53-arm match on key.code. Deep nesting to 36+ spaces.role_input_resolves_then_persists... (135L)
src/operator_env.rs3573Cross-cutting; 4 production unwrap() calls.resolve_op_uri_with_dollar_var_errors (401L), item_create (145L)
src/console/manager/render/editor.rs323125-arm match on tab.contextual_row_items (205L), render_secrets_tab (104L)
src/console/manager/render/list.rs281641 TestBackend::new() calls.render_details_pane (116L)
src/app/mod.rs2767fn run is 1141L with a 51-arm match.fn run (1141L), render_workspace_show (147L), handle_claude_token (117L)
src/console/manager/input/save.rs2734Deep nesting to 36+ spaces. Inline color re-declarations.build_confirm_save_lines (245L)
src/instance/auth.rs26075 copy-pasted provision functions. 132 deeply nested lines.
src/console/manager/state.rs2477State machine + modal definitions mixed.
src/isolation/materialize.rs2392materialize_one (245L), materialize_clone (210L).materialize_one (245L), materialize_clone (210L)
src/console/widgets/op_picker/mod.rs23314-level state machine + loader + key handler.
src/config/editor.rs226051 JackinPaths::for_tests() calls.
src/console/manager/input/mouse.rs2033handle_mouse_with_config is 129L. Mouse + seam drag logic.handle_mouse_with_config (129L)

Tier B — files 1000–2000 lines (8 files, address after Tier A)

Section titled “Tier B — files 1000–2000 lines (8 files, address after Tier A)”
FileLOCKey risk
src/console/manager/input/global_mounts.rs198442-arm + 31-arm + 29-arm matches on modal. Deep nesting.
src/isolation/finalize.rs1819assess_cleanup is 204L.
src/console/manager/input/auth.rs1767Auth tab form/modal handling.
src/workspace/token_setup.rs1610run_setup_with_runner is 126L.
src/app/context.rs1466Instance management, workspace resolution.
src/config/mod.rs1407Main config schema, auth/source policy.
src/manifest/validate.rs122236 v1alpha version strings in tests.
src/console/manager/render/mod.rs1165fn render is 201L. Central render orchestrator.

Tier C — files 800–1000 lines (10 files, lower priority)

Section titled “Tier C — files 800–1000 lines (10 files, lower priority)”
FileLOCNote
src/runtime/repo_cache.rs1145Cache + clone logic
src/runtime/attach.rs1130Duplicates DinD sidecar launch from launch.rs
src/workspace/mod.rs1056Core workspace types
src/derived_image.rs983entrypoint_dispatches_on_jackin_agent is 446L
src/console/manager/input/list.rs939List-stage key handling
src/manifest/mod.rs878Manifest loading
src/cli/workspace.rs861Workspace CLI commands
src/instance/manifest.rs851Per-instance manifest
src/console/manager/render/global_mounts.rs839Global mounts rendering
src/console/widgets/op_picker/render.rs814render_pane is 124L
  1. app/mod.rs (2767L) — highest growth (+123%); pure dispatch, lowest risk; contains the 1141L fn run
  2. instance/auth.rs (2607L) — after Phase 1.5 DRY extraction reduces it significantly
  3. operator_env.rs (3573L) — cross-cutting but well-understood dependency graph
  4. input/editor.rs + render/editor.rs (3955L + 3231L) — paired split; do together
  5. isolation/materialize.rs (2392L) — clean internal seams already identified
  6. config/editor.rs (2260L) — after the editor split patterns are established
  7. input/mouse.rs (2033L) — extract seam drag from click handling
  8. input/global_mounts.rs (1984L) — per-subtab handler extraction
  9. Tier B remainingstate.rs, render/list.rs, input/save.rs, finalize.rs, input/auth.rs, token_setup.rs, context.rs, config/mod.rs, validate.rs, render/mod.rs
  10. Tier C — address as part of normal development or when specific files become review blockers
  11. runtime/launch.rs (7575L) — LAST; hardest file, most complex test suite, behavioral spec must exist
ItemTrigger
Cargo workspace splitLOC > 150K or external consumers (currently ~91K production Rust)
rustdoc JSON → Starlight pipelineAfter //! coverage sprint
  1. Phase 1 prerequisites — snapshot tests, refreshed PROJECT_STRUCTURE.md, and the runtime/launch.rs behavioral spec
  2. Phase 1.5 DRY extractions — shared constants first (highest ROI, lowest risk), then TUI boilerplate, then auth provisioning, then Docker commands, then test infrastructure
  3. Phase 2 file splits — follow the recommended split order; do runtime/launch.rs absolutely last
  4. Documentation follow-through//! module contracts (priority: instance/, isolation/, manifest/, runtime/, tui/ all at 0% coverage), per-directory README files, ADRs
  5. Policy / workflow cleanupPROJECT_STRUCTURE.md CI gate, contributor-doc publishing, spec-workflow migration
  6. Phase 3 deferred items — workspace split and generated API docs

The re-analysis found 2 production-code dependencies from console/ into runtime/:

  1. src/console/manager/input/editor.rs:1445 — calls crate::runtime::register_agent_repo(...) when the operator types a role selector in the TUI editor
  2. src/console/manager/input/editor.rs:1536-1547 — references crate::runtime::RepoError variants in friendly_role_resolution_error()

The Cargo workspace split will need these 2 sites addressed first.

MetricValueOriginal analysis
Production Rust (src/)90,949L (116 files)~49,754L
Test code (tests/)6,758L (15 files)
Total Rust97,707L
Files > 2000 lines134
Files > 1000 lines21
Files > 800 lines31
Files with //! docs65 of 116 (56%)~47%
Files missing //! docs51 (44%)~53%
too_many_lines suppressions25
pub fn vs pub(crate) fn383 vs 42 (9.9% pub(crate))
Wildcard imports in production0 (all 91 are test-only)
Snapshot test infrastructureNone
ADR directoryNone
Per-directory README/AGENTS.mdNone
Production unwrap() calls4 (2 in operator_env.rs should use expect())

Full 2343L research document and 40-iteration history archived in git at commit b7e9fc2 on analysis/code-readability. May 2026 deep-audit findings are grounded in commit 282e235 on main.