We enforced a strict 500-line maximum on every .rs file in the Script Kit GPUI codebase — a 328,000-line Rust project — using a swarm of 25 autonomous Codex agents working in parallel.
| Metric | Value |
|---|---|
| Files over 500 lines (before) | 197 |
| Files over 500 lines (after) | 0* |
| Total commits | 8 |
| Files changed | 1,186 |
| New files created | 991 |
| Files deleted | 39 |
| Files renamed | 28 |
| Lines added | 272,380 |
| Lines removed | 250,079 |
| Net change | +22,301 lines (module boilerplate) |
*A handful of subdirectory files still being cleaned up by a final worker
| File | Lines |
|---|---|
src/ai/window.rs |
8,736 |
src/app_impl.rs |
7,425 |
src/scripts_tests.rs |
5,275 |
src/notes/window.rs |
5,097 |
src/render_builtins.rs |
4,678 |
src/main.rs |
3,974 |
src/prompts/chat.rs |
3,569 |
src/platform.rs |
3,480 |
src/stories/run_button_exploration.rs |
3,122 |
src/scriptlet_tests.rs |
2,921 |
src/ai/providers.rs |
2,914 |
src/protocol/message.rs |
2,909 |
src/app_actions.rs |
2,848 |
src/watcher.rs |
2,830 |
src/scripts/search.rs |
2,690 |
src/logging.rs |
2,563 |
src/actions/builders.rs |
2,524 |
And 180 more files between 500–2,500 lines each.
We decomposed the 197 oversized files into 20 scoped tasks and spawned a Codex agent for each:
| Agent | Scope | Files Split |
|---|---|---|
codex-app-impl |
src/app_impl* |
7,425-line monolith → modules |
codex-ai-window |
src/ai/* |
8,736-line window.rs → submodules |
codex-main-rs |
src/main.rs |
3,974-line main → entry modules |
codex-notes-window |
src/notes/* |
5,097-line window → submodules |
codex-render-builtins |
src/render_builtins* |
4,678 lines → per-builtin files |
codex-platform |
src/platform* |
3,480 lines → platform modules |
codex-prompts |
src/prompts/* |
chat.rs + 5 others |
codex-actions-dialog |
src/actions/dialog* |
19 dialog test files (~2K each) |
codex-actions-builders |
src/actions/* |
builders.rs + non-dialog files |
codex-protocol |
src/protocol/* |
message.rs + types.rs |
codex-app-star |
src/app_*.rs |
6 app_ files |
codex-tests |
src/*_tests.rs |
3 large test files → chunks |
codex-stories |
src/stories/* |
story files |
codex-scripts |
src/scripts/* |
search.rs + others |
codex-config-theme |
src/config/*, src/theme/* |
config + theme modules |
codex-designs |
src/designs/* |
design system files |
codex-components |
src/components/* |
7 component files |
codex-terminal |
src/terminal/* |
5 terminal files |
codex-render-prompts |
src/render_prompts/* |
arg.rs + form.rs |
codex-toplevel-misc |
src/*.rs |
55+ remaining top-level files |
With 20 agents editing the same Rust codebase simultaneously, we ended up with 499 compile errors from broken imports, lost serde derives, and visibility issues. We spawned 6 more agents to fix them:
| Agent | Task | Result |
|---|---|---|
codex-fix-protocol-types |
Fix serde imports in protocol/ | ✅ Done in ~2 min |
codex-fix-actions |
Fix builder imports in actions/ | ✅ Done |
codex-fix-prompts |
Fix visibility in prompts/ | ✅ Done |
codex-fix-components |
Fix module paths in components/ | ✅ Done |
codex-fix-remaining |
Fix everything else (broadest scope) | ✅ 499→0 errors |
codex-fix-clippy-tests |
Fix clippy + test compilation | 🔄 Running |
The most interesting challenge was the error cascade from parallel agents:
- Agent A splits
protocol/types.rsinto submodules - Agent B splits
actions/builders.rswhich imports fromprotocol/types - Agent C splits
prompts/which imports from both - All three commit independently → import paths break across module boundaries
The fix-up phase had to resolve these cross-cutting concerns — primarily:
- 155 missing
#[serde]attributes (derive macros lose scope ininclude!()files) - 42 missing
Serialize/Deserializederives - Visibility downgrades (types that were
pubwithin a file become private when moved to submodules)
Each agent used one of two approaches:
For files with clear logical sections:
src/platform.rs (3,480 lines)
→ src/platform/
mod.rs (re-exports)
accessibility.rs (340 lines)
window_ops.rs (290 lines)
display.rs (380 lines)
...
For tightly-coupled code that can't easily separate imports:
src/app_impl.rs (7,425 lines)
→ src/app_impl.rs (include! wrapper)
src/app_impl/
mod.rs
startup.rs (480 lines)
handlers.rs (450 lines)
lifecycle.rs (390 lines)
...
-
Parallel agents + shared codebase = merge hell. The split phase went fast but the fix-up phase was essential. Budget 30% of time for cross-agent conflict resolution.
-
Serde derives are the #1 casualty of file splits. When you
include!()a file, it doesn't get its ownuseimports — they come from the parent. But when you make it a proper module, every file needs its own imports. -
The biggest agent always finishes last.
codex-toplevel-mischad 55 files and took 3x longer than any other agent. Better to split into 3-4 agents from the start. -
File claim locks prevent duplicate work but become stale when agents die. We had to manually release claims from a killed agent to unblock others.
-
cargo checkpassing ≠cargo clippy --all-targetspassing. Test targets have additional import requirements that only surface with--all-targets.
f650654 refactor: split all .rs files to be under 500 lines
37fc9d0 fix(components): repair split module imports in component renders
53fec3f refactor(stories): split oversized story modules into submodules
ddd673f refactor(ai-window): split window.rs into focused modules
e2a47d1 refactor(render_builtins): split builtin renderers into module files
5af3a86 test(app_impl): update source-audit paths after module split
4937a03 refactor(app_impl): split ScriptListApp impl into modules
c3ef366 feat: add module docs, agent tooling, and streamlined AGENTS.md
Generated from the Script Kit GPUI codebase — a Rust (GPUI) + TypeScript (Bun) desktop application framework.