Agent Team Orchestration at Scale: Wave-Based Execution with File Ownership
Agent Team Orchestration at Scale: Wave-Based Execution with File Ownership
Problem
Large feature implementations and code review remediations involve many agents working in parallel on overlapping codebases. Without careful coordination, agents:
- Overwrite each other’s changes to shared files
- Make incompatible changes that break compilation
- Run out of context budget before committing their work
- Create merge conflicts that are difficult for the leader to resolve
The INK-72 Multi-Device Sync epic required:
- Implementation: 6 agents across 6 dependency-ordered waves (13 issues, 33 points)
- Review: 8 specialized review agents in parallel
- Remediation: 4 agents across 2 dependency-ordered waves (57 findings)
Root Cause
Uncoordinated parallel execution fails because:
- File contention: Multiple agents editing the same file creates race conditions
- Dependency chains: Later agents need output from earlier agents (trait changes, migrations, etc.)
- Context limits: Complex agents hit context window limits before finishing, losing uncommitted work
- Compilation coupling: Rust’s type system means a trait change in one crate breaks all dependents
Solution
1. Wave-Based Execution with Dependency Gates
Organize agents into waves where each wave runs in parallel, and waves execute sequentially:
Wave 1: [schema-agent, loro-agent] ← Foundation (parallel) ↓ Gate: cargo check passes, leader commitsWave 2: [auth-agent, infra-agent] ← Auth + Push (parallel) ↓ Gate: cargo check passes, leader commitsWave 3: [sync-core-agent] ← Pull (serial, needs Wave 2 traits) ↓ Gate: cargo check + test passes, leader commits...Gate criteria: Between waves, the leader runs compilation and tests, commits all work, then launches the next wave. This ensures each wave starts from a known-good state.
2. Strict File Ownership Boundaries
Each agent gets an exclusive set of files. No two agents touch the same file in the same wave:
## Wave 2 File Ownership
**sync-engine-agent** owns:
- crates/application/src/sync/sync_engine.rs- crates/application/src/sync/push_block_updates.rs- crates/application/src/sync/pull_block_updates.rs- crates/application/src/sync/services.rs (batch push method ONLY)- apps/desktop/src-tauri/src/sync.rs
**frontend-test-agent** owns:
- apps/desktop/src-react/lib/realtime-sync.ts- crates/application/src/sync/disable_workspace_sync.rs- crates/application/src/sync/enqueue_block_update.rs- crates/application/src/auth/get_current_user.rs (logging ONLY)
DO NOT MODIFY files owned by other agents.When a file needs changes from multiple concerns (e.g., services.rs needs both a batch push method and a metadata
trait change), either:
- Assign it to one agent with both responsibilities, or
- Split changes across waves (Wave 1 agent does the trait change, Wave 2 agent adds the method)
3. Commit Strategy: Leader vs Self-Wiring
3a. Leader Commits All Work (Default)
Agents never commit directly. The leader:
- Waits for all agents in a wave to complete
- Reviews the changes (quick scan for obvious issues)
- Runs
tools/precheck.sh --fix(auto-fixes formatting, then validates gitleaks, clippy, tests, oxlint, typecheck) - Stages files in logical groups
- Creates discrete commits with clear scope
This prevents:
- Agents creating half-baked commits that break the build
- Context-exhausted agents losing uncommitted work
- Merge conflicts from concurrent git operations
# Leader commits Wave 1 in two logical groups:git add supabase/ crates/infrastructure/sqlite/src/sync/metadata_storage.rs ...git commit -m "fix(sync): schema and data integrity review remediation (INK-72)"
git add apps/desktop/src-tauri/src/state.rs crates/infrastructure/supabase/...git commit -m "fix(auth): auth singleton, config system, and layer violation remediation (INK-72)"Use this mode when:
- Agents may hit context limits before finishing
- Changes are mutative (refactoring existing signatures, restructuring init logic)
- Multiple agents touch closely related files across waves
- You want maximum leader control over commit structure
3b. Self-Wiring Mode (bypassPermissions)
With bypassPermissions mode, agents modify framework files (state.rs, main.rs, commands/mod.rs, lib.rs)
directly and commit their own work. The leader’s wave-gate role simplifies from “apply diffs and commit” to “verify
compilation, run tests, regenerate artifacts.”
Agent workflow in self-wiring mode:
- Implement domain/application/infrastructure changes
- Wire framework files directly (add fields to
AppState, register commands inmain.rs, addmoddeclarations) - Create
WIRING.mdas a verification checklist (not a diff to apply) - Run
cargo check,cargo clippy,cargo test - Commit their own work with discrete commit messages
Leader gate workflow:
- Run
tools/precheck.sh --fix(auto-fixes formatting, validates clippy, tests, oxlint, typecheck) - Regenerate artifacts (
pnpm generate:types) - Clean up
WIRING.mdfiles - Commit any leader-only work (bindings, cleanup)
Use this mode when:
- Changes are additive (new module, new field, new command registration)
- Each agent’s framework changes don’t overlap within a wave
bypassPermissionsmode is enabled for all agents- Agent prompts are focused enough to avoid context exhaustion
Key insight: Self-wiring works because framework wiring is typically additive — adding a new field to
AppState, appending a .invoke_handler() call, adding a mod declaration. Mutative changes (refactoring state
initialization, changing handler signatures, restructuring DI) remain leader-owned.
WIRING.md as hedge: Even in self-wiring mode, agents still create WIRING.md. It serves as a verification checklist
at the gate and a fallback if an agent’s self-wiring fails to compile.
4. Agent Prompt Design
Each agent’s prompt includes:
- Explicit file ownership list with “ONLY modify these” and “DO NOT MODIFY” sections
- Pre-existing state context (“Wave 1 committed, codebase compiles, all tests pass”)
- Verification instructions (“Run cargo check, cargo test, cargo clippy when done”)
- Communication protocol (“Send message to team-lead with summary and test results”)
- Bypass permissions mode to avoid interactive approval delays
5. Review Agent Specialization
For code reviews, use 5-8 specialized agents rather than one general reviewer:
| Agent | Focus | Value |
|---|---|---|
| code-quality-reviewer | Clarity, patterns, DRY | Catches style issues |
| security-sentinel | OWASP, auth, data protection | Catches vulnerabilities |
| performance-oracle | N+1, algorithms, resources | Catches bottlenecks |
| architecture-strategist | Layers, coupling, patterns | Catches structural issues |
| test-reviewer | Coverage, quality, edge cases | Catches test gaps |
| domain-expert | Language idioms, framework | Catches language-specific issues |
| data-integrity-guardian | Migrations, transactions | Catches data safety issues |
| observability-analyst | Logging, monitoring | Catches operational gaps |
Each agent reviews the same diff but through its specialized lens. Findings are collected by the leader and deduplicated.
Implementation Notes
Team Sizing
- Implementation: 1 agent per work stream (e.g., auth, sync engine, frontend). Avoid more than 6 concurrent agents — context management overhead grows.
- Review: 5 agents for standard reviews, 8 for deep reviews. All run in parallel since they’re read-only.
- Remediation: Group findings by subsystem. 2-4 agents with strict file boundaries.
Handling File Overlap in Remediation
When review findings span shared files, the leader must decide:
- Split by subsystem (preferred): Group findings that touch the same files into one agent
- Split by wave: If findings have dependencies, put dependent changes in later waves
- Accept pragmatic grouping: Sometimes clean separation isn’t possible. Group by “compiles together” rather than by issue ID
Monitoring Agent Progress
- Check
TaskListafter each agent completes - Use
SendMessagefor status queries (don’t use terminal tools to spy on agents) - Set realistic expectations: each agent takes 3-8 minutes for moderate work
- Be patient with idle agents — idle after message delivery is normal
Known Pitfalls
- Late-phase agents hitting context limits: Agents with large prompts or many file reads exhaust context.
Mitigation: keep agent prompts focused, use
bypassPermissionsmode, plan for leader to commit on their behalf. If exhaustion occurs, use the continuation agent pattern — seedocs/solutions/workflow-issues/agent-context-exhaustion-and-continuation.md. - Stale team members after context loss: If the leader session loses context, old team agents remain as zombie processes. Always send shutdown requests before creating new teams.
- Test count as progress indicator: Track
cargo testcount across waves. If test count doesn’t increase after a “test coverage” agent runs, investigate.
Prevention
Orchestration Checklist
- Dependencies mapped between issues/findings before agent assignment
- Waves ordered by dependency (foundation first)
- File ownership explicitly assigned per agent (no overlaps within a wave)
- Agent prompts include “DO NOT MODIFY” lists
- Commit mode decided per wave (leader-commits vs self-wiring)
- Leader commits at wave boundaries (not agents) — or verifies agent commits in self-wiring mode
- Gate criteria defined for each wave (compilation, tests, etc.)
- Gate criteria includes
tools/precheck.sh --fixfrom main repo - Shutdown protocol for team cleanup
Scaling Guidelines
| Epic Size | Agents | Waves | Review Agents | Notes |
|---|---|---|---|---|
| 1-3 issues | 1-2 | 1 | 2 (quick) | |
| 4-8 issues | 2-4 | 2-3 | 5 (standard) | |
| 9-15 issues | 4-8 | 4-6 | 8 (deep) | Combine polish/verification issues in later waves |
| 15+ issues | Split into sub-epics first | — | — |
Results
INK-72 Multi-Device Sync (Implementation + Review + Remediation)
The wave-based approach delivered:
- 16 commits (12 feature + 4 remediation) — all clean, discrete, single-concern
- 921 tests passing (14 new tests added during remediation)
- 57 review findings addressed (12 P1, 25 P2, 20 P3 — all fixed)
- Zero merge conflicts between agents
- Zero compilation failures at wave gates
INK-129 Async Migration (Review + Remediation)
Post-merge review of async migration (5 commits, 40 files, +2134/-774 lines):
- Review: 5 specialized agents in parallel identified 15 findings (3 P1, 7 P2, 5 P3)
- Remediation: 11 agents across 3 waves, 15 Linear issues (INK-190–204)
- 13 commits — all discrete, single-concern, passing pre-commit hooks
- 24 new tests (8 composite unit tests + 16 integration tests)
- All 15 issues closed as Done
- Zero merge conflicts between agents
- Key patterns documented: SQLite queue full-table scan anti-pattern, Rust async lock anti-patterns (mutex across await + TOCTOU token refresh)
Notable: Wave 3 had a compile-time dependency between connection-cache agent and two downstream agents
(composite-tests, e2e-tests). The dependency was resolved via inter-agent messaging — the connection-cache agent
fixed remaining Self::open_db() references, unblocking the other agents without leader intervention.
INK-232 Types System (Implementation — Self-Wiring Mode)
Full-stack types system epic using self-wiring mode for the first time:
- 9 issues, 4 waves, 8 agent instances
- 6 commits (4 feature + 1 chore + 1 leader gate)
- Agents modified
state.rs,main.rs,commands/mod.rs,lib.rsdirectly - Zero merge conflicts between agents
- Zero compilation failures at wave gates
WIRING.mdcreated by agents as verification hedge, deleted after leader confirmed compilation- Key difference from prior epics: leader role shifted from “apply diffs” to “verify completeness”
Wave structure:
- Wave 1 (2 agents): Domain entity + migration/repository — foundation layer
- Wave 2 (2 agents): Use cases + Tauri commands — application + framework wiring
- Wave 3 (2 agents): Frontend components + collection views — UI layer
- Wave 4 (2 agents): Import type mapping + TypeScript binding regeneration — integration
Each wave’s agents self-wired framework files and committed their own work. The leader verified compilation and tests at each gate, then regenerated TypeScript bindings after Wave 4.
INK-333 Cloud Template Catalog (Review → Remediation Pipeline)
First use of the full review→remediation pipeline — /workflow:review produces prioritized findings, which feed
directly into a remediation agent team plan:
- 22 findings (5 P1, 10 P2, 7 P3) from deep code review
- 3 waves, 6 agents, leader-commits mode
- 4 commits (wave 1 + review findings + wave 2 + wave 3)
- 2 findings deferred to follow-up issues (INK-345, INK-346)
Key patterns discovered:
- Cross-agent field rename reconciliation: Wave 3A renamed
TemplateCatalogEntry.file→storage_pathin domain + frontend. Wave 3B wrote Playwright tests using the oldfilename (instructed to for safety). Leader reconciled by updating test mock data and assertions after both agents completed. Lesson: when multiple agents in the same wave touch data models and test fixtures, plan for leader reconciliation of shared field names at the wave gate. - lint-staged failure drops staged files: Pre-commit clippy failure during Wave 2 commit caused lint-staged to
unstage all 16 files. Only 3 files made it into the first commit; a second commit caught the remaining 6. See
docs/solutions/workflow-issues/lint-staged-failure-drops-staged-files.md. - Specta preserves snake_case: Plan assumed
storage_path→storagePathin TypeScript. Specta actually generatesstorage_path(preserving snake_case). Frontend agent discovered and adapted at implementation time.
Wave structure:
- Wave 1 (3 agents): App layer fixes + infra hardening + CI/CD hardening — parallel foundation
- Wave 2 (1 agent): Framework wiring — commands, state, new use case (depends on Wave 1)
- Wave 3 (2 agents): Frontend auth/UX + Playwright integration tests — parallel, depends on Wave 2
INK-233 Block Content Types (Implementation — Continuation Agent Pattern)
Full-stack block content types epic, first use of the continuation agent pattern:
- 8 issues, 4 waves, 6 agent instances (5 planned + 1 continuation)
- 4 commits (1 per wave, leader-commits mode)
- Self-wiring mode with
bypassPermissionsfor all agents - Zero merge conflicts, zero compilation failures at wave gates
Key patterns:
- Foundation wave pre-inclusion: Wave 1 pre-included domain methods (
searchable_text(),to_markdown(), validation methods) specified in Wave 2 issues. Added ~30 lines but eliminated domain file conflicts for 2 parallel Wave 2 agents. - Continuation agent: Wave 4 agent (
insert-flow) exhausted context after completing application layer. Leader detected viagit status(partial modifications), spawnedinsert-flow-2with remaining scope only. Combined output: 12 files, 798 insertions, all gates passed. - Bonus feature discovery: Wave 4 continuation agent proactively added
upload_attachment_bytesTauri command for clipboard paste support — not in the original plan but naturally needed for theImageBlockDroppaste handler.
Wave structure:
- Wave 1 (1 agent): Domain enum + migration V009 + SQLite storage — foundation
- Wave 2 (2 agents): Metadata API + FTS5 indexing || markdown export + badge — parallel backend
- Wave 3 (1 agent): TipTap ImageBlock node view — frontend rendering
- Wave 4 (1+1 agents): Insert menu + drag-drop — full-stack (exhausted → continued)
See docs/solutions/workflow-issues/agent-context-exhaustion-and-continuation.md for the continuation pattern details.
INK-235 Layout Definition and Rendering (Implementation — Largest Wave Count)
Largest orchestrated epic to date — 6 waves, 11 agent instances, zero conflicts:
- 14 issues, 6 waves, 11 agent instances
- 12 commits (agent self-commits + leader bindings regeneration)
- Self-wiring mode (
bypassPermissions) for all agents - Zero merge conflicts across all 11 agents — including waves where 3 agents ran in parallel
- Zero compilation failures at any wave gate
Key patterns:
- Shared file safety at 3-agent parallelism: Wave 5 had 3 agents running simultaneously, with agents B and C both
extending
LayoutPicker.tsx. Changes were additive (different sections) — no conflict. This validates that self-wiring mode scales beyond 2-agent parallelism when changes are additive and touch different sections. - Cross-wave file evolution:
PageView.tsxwas modified by Wave 4A (grid rendering), Wave 4B (layout picker integration), and Wave 6 (type assignment badge). Each wave built on the prior’s committed state with zero conflicts. - Context recovery across sessions: Orchestration spanned 2 leader sessions (context exhaustion at Wave 3 boundary). Continuation session recovered state from git log + agent task status with no loss of orchestration context.
- Per-cell LoroDoc architecture: Required new per-block Tauri commands (
get_block_content_snapshot_by_id,save_block_content_by_id) in Wave 1, enabling Wave 4’s multi-editor grid without cross-cell CRDT contamination.
Wave structure:
- Wave 1 (1 agent): Domain + schema — Layout value object, V010 migration, per-block BLOB commands
- Wave 2 (3 agents): Layout definitions CRUD || markdown export || sync metadata — parallel backend
- Wave 3 (1 agent): Apply/remove/assign layout use cases — depends on Waves 1+2
- Wave 4 (2 agents): Grid editor + EmptyCell || Layout picker + toolbar — parallel frontend
- Wave 5 (3 agents): Keyboard navigation || compatibility check + conflict dialog || custom layout creator — parallel enhancements
- Wave 6 (1 agent): Type-layout association — depends on INK-232 types system
New architectural pattern documented: docs/solutions/architecture/multi-editor-grid-per-cell-crdt.md
INK-253 Property Value Insertion (Implementation — Cross-Layer Feature)
8 issues across 4 waves, spanning frontend (TipTap, React, CSS), markdown serialization, and Rust infrastructure (FTS5 integration tests).
Key characteristics:
- Pure frontend + infrastructure — no domain or application layer changes needed
- Cross-context session — continued from a planning session into execution across context compaction boundary
- 3-agent parallel Wave 4 — markdown write-back (Rust), slash command (TypeScript), click-to-navigate (TypeScript) with zero shared files
Wave structure:
- Wave 1 (1 agent): PropertyRef TipTap inline node — foundational extension
- Wave 2 (2 agents): Markdown serialization || render-time resolution — both touch
PropertyRef.tsin non-overlapping sections - Wave 3 (2 agents):
{{autocomplete (frontend) || FTS5 verification (Rust) — completely different layers - Wave 4 (3 agents): Markdown write-back (Rust) ||
/propertyslash command (TypeScript) || click-to-navigate (TypeScript) — zero file overlap
Lessons reinforced:
- Wave 2 shared
PropertyRef.tssafely because agents modified different sections (parseHTML vs NodeView rendering) - Wave 3 demonstrated cross-language parallelism (TypeScript + Rust) as the safest form — zero conflict risk
- Wave 4 validated 3-agent parallel with distinct file ownership across both TypeScript and Rust codebases
New architectural patterns documented:
docs/solutions/patterns/tiptap-extension-option-mutation-for-nodeview-rerender.mddocs/solutions/architecture/fts5-unicode61-implicit-syntax-tokenization.md
INK-254 WikiLink Round-Trip Safety (Implementation — Issue Combining Pattern)
10-issue epic introducing [[Display|slug]] wiki-link syntax with reference index, demonstrating late-wave issue
combining:
- 10 issues, 4 waves, 6 agent instances (vs 10 if 1:1)
- 7 commits (5 feature + 1 docs, leader-commits for Waves 3-4)
- Mixed commit mode: self-wiring (Waves 1-2), leader-commits (Waves 3-4)
- Zero merge conflicts, zero compilation failures at wave gates
- Zero continuation agents needed (aggressive combining kept per-agent scope within context budget)
Key pattern — Late-Wave Issue Combining:
- Wave 3: 3 issues → 2 agents. INK-316 (export verification) and INK-317 (Loro CRDT confirmation) were lightweight verification tasks combined into a single agent. INK-315 (Import rewrite) remained standalone due to substantive implementation scope.
- Wave 4: 2 issues → 1 agent. INK-318 (Ghost link UI) and INK-319 (Heading navigation) shared the same component layers (WikiLink.ts, InklingsEditor.tsx, PageView.tsx). Combining prevented file ownership conflicts that would have required serialization into sub-waves.
When to combine issues into fewer agents:
- Later waves where foundation is stable and scope is verification/polish
- Shared file layers where splitting would create ownership conflicts
- Lightweight scope (verification, docstrings, round-trip tests) that doesn’t justify a dedicated agent
- Combined scope fits in ~40% of context budget (leave margin for iteration)
When NOT to combine:
- Foundation waves (Waves 1-2) where each issue introduces new architectural concepts
- Cross-layer implementations spanning 4+ layers (domain → infrastructure → application → framework → frontend)
- Issues with different dependency chains that could execute in separate waves
Result: 10 issues completed with 40% fewer agent instances than 1:1 assignment. No context exhaustion, no conflicts, no rework.
Wave structure:
- Wave 1 (2 agents): Parser + domain || reference index migration — parallel foundation
- Wave 2 (3 agents): Index-backed queries || index-backed rename || TipTap extension — parallel core features
- Wave 3 (2 agents): Import rewrite || export + Loro verification (combined) — parallel ecosystem
- Wave 4 (1 agent): Ghost link UI + heading navigation (combined) — single polish agent
References
- Branch:
matt/ink-72-multi-device-sync(16 commits) - Branch:
matt/ink-129-convert-supabase-block_on-to-async(merged to main, 13 remediation commits) docs/solutions/workflow-issues/agent-team-uncommitted-work.md— earlier pattern for single-wave teamsdocs/solutions/workflow-issues/batched-commits-anti-pattern.md— why per-story commits matterdocs/solutions/database-issues/sqlite-queue-full-table-scan-anti-pattern.md— O(n²) queue pattern from INK-129 reviewdocs/solutions/logic-errors/rust-async-lock-anti-patterns.md— async lock patterns from INK-129 reviewdocs/solutions/workflow-issues/lint-staged-failure-drops-staged-files.md— lint-staged stash behavior from INK-333- Branch:
main(INK-232 commits390af08..2682477) - Branch:
main(INK-333 remediation commitsc02eeee..0309aba) - Branch:
matt/ink-233-introduce-block-content-types(INK-233 commitse6c2ff6..2e8721e) docs/solutions/workflow-issues/agent-context-exhaustion-and-continuation.md— continuation agent pattern from INK-233- Branch:
matt/ink-235-layout-definition-and-rendering(INK-235 commitsd4a8566..b376190) docs/solutions/architecture/multi-editor-grid-per-cell-crdt.md— per-cell CRDT multi-editor pattern from INK-235- Branch:
feat/INK-253in worktree.claude/worktrees/ink-253/(INK-253 commitsff430e0..aa7ffaf) docs/solutions/patterns/tiptap-extension-option-mutation-for-nodeview-rerender.md— NodeView re-render pattern from INK-253docs/solutions/architecture/fts5-unicode61-implicit-syntax-tokenization.md— FTS5 tokenizer insight from INK-253- Branch:
feat/INK-254(INK-254 commitse7436a4..f9455e3, worktree at.claude/worktrees/ink-254/)
Agent Context Exhaustion and Continuation: Spawning Replacement Agents Mid-Wave Next
Derive Copy Cross-Agent Ripple: Adding Copy to a Shared Type Breaks Downstream Clippy
Was this page helpful?
Thanks for your feedback!