Monorepo Execution Controller
Overview
A new monorepo pack for the agentic-skills library that makes the full skill pipeline monorepo-aware. Instead of duplicating skills (like the -kanban variants), the pack uses an augmentation injection pattern — monorepo pack skills add pre/post steps to existing global skill contracts, injecting workspace detection, lane-spec generation, boundary guarding, and scoped shipping into the standard plan → execute → ship lifecycle.
The pack targets pnpm workspaces + Turborepo as the first-class monorepo stack, with detection via pnpm-workspace.yaml and turbo.json. When Turborepo is present, skills defer to turbo run for build/test/lint tasks to leverage its caching and dependency-aware ordering.
V1 ships four skills: mono-detect, mono-run, mono-ship, and mono-guard. V2 expands to planning, analysis, and migration skills.
Goals
- Make the skill library monorepo-aware without duplicating every global skill.
- Provide automated lane dispatch for parallel agent-team execution across packages, with structured lane-spec artifacts and boundary enforcement.
- Keep specs, research, tasks, and roadmap at the root level with package-scope tags — no per-package directory sprawl.
- Handle cross-cutting work (shared packages, root config) safely by enforcing serial execution for cross-cutting steps.
- Stop-all-lanes failure semantics: any lane failure halts remaining lanes and preserves worktree state for inspection.
- Support step-at-a-time execution by default, with
--phaseand--pipelineflags for broader execution.
Non-Goals
- Supporting non-pnpm workspace managers (npm, yarn, Lerna, Nx) in v1. Detection stubs may exist but behavior is pnpm + Turbo only.
- Multi-repo → monorepo migration. Only single-app → monorepo is planned (v2).
- Per-package task files (
packages/api/tasks/todo.md). All task management stays root-level. - Replacing
/mono-planor/mono-guardglobally — these existing global skills remain available; the pack skills (mono-run,mono-ship) call them internally. - GitHub Actions or CI integration.
Detailed Design
Pack Structure
packs/monorepo/
├── PACK.md # Pack description, install instructions, skill list
├── claude/
│ ├── mono-detect/SKILL.md # Workspace detection and package graph
│ ├── mono-run/SKILL.md # Augmented /run with lane dispatch
│ ├── mono-ship/SKILL.md # Scoped shipping with per-package validation
│ └── mono-guard/SKILL.md # Pack-local reference to boundary enforcement
├── codex/
│ ├── mono-detect/SKILL.md
│ ├── mono-run/SKILL.md
│ ├── mono-ship/SKILL.md
│ └── mono-guard/SKILL.md
└── scripts/
├── mono-detect.sh # Detect workspace manager, enumerate packages, build dep graph
├── lane-spec-validate.sh # Validate lane-spec JSON against schema
└── monorepo-validate.sh # Pack-level validation (contracts, tags, detection)
Monorepo Detection (mono-detect)
mono-detect is the foundation skill. It detects the workspace structure and outputs a package graph that other skills consume.
Detection order:
- Check for
pnpm-workspace.yaml→ pnpm workspaces - Check for
turbo.json→ Turborepo overlay - If neither found, exit with "not a detected monorepo" and suggest
/mono-migrate(v2)
Output: .agents/monorepo.json
{
"workspace_manager": "pnpm",
"build_orchestrator": "turborepo",
"root": "/absolute/path",
"packages": [
{
"name": "@scope/api",
"path": "packages/api",
"dependencies": ["@scope/shared-lib"],
"devDependencies": ["@scope/test-utils"],
"scripts": {
"build": "tsc",
"test": "vitest",
"lint": "eslint ."
}
}
],
"dependency_graph": {
"@scope/api": ["@scope/shared-lib"],
"@scope/web": ["@scope/shared-lib", "@scope/api"],
"@scope/shared-lib": []
},
"turbo_pipelines": ["build", "test", "lint"],
"detected_at": "2026-05-03T10:00:00Z"
}
Staleness: mono-detect re-runs if pnpm-workspace.yaml, turbo.json, or any package.json has a newer mtime than .agents/monorepo.json.
Structured Lane-Spec Artifact
Following the approval-packet pattern, lane specs use a JSON + committed Markdown mirror:
Machine-readable: .agents/lane-specs.json
{
"phase": "Phase 22: API Auth Refactor",
"source_roadmap_hash": "abc123",
"lifecycle": "draft",
"cross_cutting_steps": [
{
"step": "22.1",
"description": "Update shared auth types",
"packages": ["shared-lib"],
"scope": "cross-cutting",
"mode": "serial"
}
],
"lanes": [
{
"id": "api-auth",
"step": "22.2",
"description": "Refactor API auth middleware",
"packages": ["api"],
"owns": ["packages/api/src/auth/"],
"must_not_edit": ["pnpm-lock.yaml", "turbo.json", "packages/web/", "packages/shared-lib/"],
"depends_on": ["22.1"],
"mode": "parallel"
},
{
"id": "web-auth-ui",
"step": "22.3",
"description": "Update web auth components",
"packages": ["web"],
"owns": ["packages/web/src/auth/"],
"must_not_edit": ["pnpm-lock.yaml", "turbo.json", "packages/api/", "packages/shared-lib/"],
"depends_on": ["22.1"],
"mode": "parallel"
}
]
}
Lifecycle: draft → approved → dispatched → integrated | failed
draft: Generated bymono-runfrom roadmap execution profile.approved: User reviews and approves in plan mode.dispatched: Parallel agents are launched.integrated: All lanes completed successfully,/mono-guardpost-integration passed.failed: A lane failed; all lanes halted. Worktree state preserved.
Human-readable mirror: tasks/lane-specs.md (committed)
Package-Scope Tags
Specs and roadmap phases use YAML frontmatter to declare package scope:
---
packages: [api, web]
scope: cross-cutting
---
Valid scope values:
cross-cutting— touches shared packages or root config; forces serial executionpackage-scoped— touches only the listed packages; eligible for parallel dispatchroot-only— touches only root-level config/scripts; forces serial execution
When scope is omitted, it defaults to package-scoped if packages has exactly one entry, or cross-cutting if it has multiple.
Augmented Execution: mono-run
mono-run augments /run with monorepo-aware dispatch. It does not replace /run — it wraps it with pre/post steps.
Pre-execution injection:
- Run
mono-detectif.agents/monorepo.jsonis stale or missing. - Read the current phase's execution profile from
tasks/roadmap.md. - If the phase mode is
agent-teamand the project is a detected monorepo: - If the phase mode is
serialor the project is not a monorepo, delegate directly to/run.
a. Parse lane definitions from the execution profile. b. Generate .agents/lane-specs.json and tasks/lane-specs.md. c. Run /mono-guard pre-flight validation on the lane specs. d. Enter plan mode with the lane specs for user approval.
Dispatch (after approval):
- Execute cross-cutting steps serially in the main agent first.
- For each parallel wave (lanes with satisfied
depends_on): - After all parallel lanes complete successfully:
a. Launch worktree-isolated agents, one per lane. b. Each agent receives its owns, must_not_edit, and step instructions. c. If Turborepo is available, agents use turbo run <task> --filter=<package> for build/test/lint. d. Monitor all agents. On any failure: halt remaining agents, preserve all worktree state, update lane-spec lifecycle to failed, report which lane failed and why.
a. Run /mono-guard post-integration to verify no boundary violations. b. Update lane-spec lifecycle to integrated. c. Hand off to /mono-ship or continue to next step.
Flags:
- (default): Execute the next incomplete step.
--phase: Execute all steps in the current phase (cross-cutting serial, then parallel waves, then integration).--pipeline: Plan → execute → ship the current phase in sequence.
Augmented Shipping: mono-ship
mono-ship augments /ship with package-scoped validation and shipping.
Pre-ship injection:
- Run
mono-detectif stale. - Read
.agents/lane-specs.jsonto understand which packages were modified. - For each modified package:
- Run transitive dependent tests: use the dependency graph from
.agents/monorepo.jsonto test packages that depend on modified packages. - If any validation fails, stop and report. Do not proceed to shipping.
a. Run package-scoped tests: turbo run test --filter=<package> (or pnpm --filter <package> run test). b. Run package-scoped lint: turbo run lint --filter=<package>. c. Run package-scoped build: turbo run build --filter=<package>.
Ship:
- Delegate to
/shipfor the actual commit/push/deploy cycle. - Update
tasks/lane-specs.mdwith shipping status. - If
--pipelinewas used, plan the next phase via/roadmap.
Boundary Enforcement: mono-guard
The existing global /mono-guard skill handles lane boundary validation. The pack's mono-guard is a thin reference that ensures:
- Pre-flight: Lane specs are valid,
ownspaths are disjoint,must_not_editincludes lockfiles and root config, dependency ordering is a valid DAG. - Post-integration: Actual file changes match declared
ownspaths, no lane wrote outside its boundary, no lockfile modifications from parallel agents.
Cross-Cutting Execution Safety
Steps tagged scope: cross-cutting or touching packages listed in multiple lanes:
- Always execute serially in the main agent (never dispatched to parallel worktrees).
- Must complete before any parallel lanes that
depends_onthem. - May modify shared packages, root config, and lockfiles (the main agent is the only context where lockfile writes are permitted).
- After completion, parallel lanes see the updated state via worktree creation from the post-cross-cutting commit.
Data Model
.agents/monorepo.json
- Workspace detection output. Regenerated when workspace config files change.
- Contains package list, dependency graph, Turbo pipeline awareness.
- Read by all monorepo pack skills.
.agents/lane-specs.json
- Per-phase lane dispatch plan. Lifecycle:
draft → approved → dispatched → integrated | failed. - Contains cross-cutting steps, parallel lanes with
owns/must_not_edit/depends_on. - Consumed by
mono-runfor dispatch,mono-guardfor validation,mono-shipfor scoped testing.
tasks/lane-specs.md
- Committed Markdown mirror of
.agents/lane-specs.json. - Human-reviewable record of lane decisions and outcomes.
Package-scope tags in existing files
tasks/roadmap.mdphases:packages:frontmatter field on execution profile sections.specs/*.md:packages:frontmatter field indicating which packages the spec applies to.research/*.md:packages:frontmatter field when research is package-specific (most research stays unscoped).
Edge Cases
- Single-package monorepo: A workspace with only one package.
mono-rundetects this and falls back to standard/run(no lane dispatch needed). Logged as advisory. - Circular dependencies in package graph:
mono-detectvalidates the dependency graph is a DAG. If cycles are found, it errors with the cycle path and suggests fixingpackage.jsondependencies. - Lane spec drift: If
tasks/roadmap.mdis modified after lane specs are approved but before dispatch,mono-rundetects the hash mismatch (source_roadmap_hash) and requires re-approval. - Worktree cleanup on failure: Failed lanes leave worktrees intact for inspection.
mono-run --cleanupremoves stale worktrees from previous failed runs. - No Turborepo: If
turbo.jsonis absent, skills fall back topnpm --filter <package> run <script>. Build/test ordering follows the dependency graph from.agents/monorepo.jsoninstead of Turbo's pipeline. - New package added mid-phase: If a lane creates a new package (e.g.,
packages/new-service/), it must declare the path inowns.mono-guardpost-integration allows new directories within declaredownspaths. - Root-only changes: Phases that only touch root config (e.g., updating
turbo.jsonpipeline config) usescope: root-onlyand run serially without lane dispatch. - Mixed pack project: If
.agents/project.jsonhasproject_scopeswith path-based domain designations,mono-detectincludes these scope annotations in the package graph so domain-aware skills can route correctly.
Test Plan
Script-based validation matching the existing repo validation pattern:
scripts/monorepo-validate.sh
- Contract compliance: All monorepo pack skills reference the augmentation injection pattern (pre/post steps, not full copies).
- Lane-spec schema:
.agents/lane-specs.jsonfixtures pass schema validation (required fields: phase, lifecycle, lanes with owns/must_not_edit/depends_on). - Detection correctness:
mono-detect.shcorrectly identifies pnpm-workspace.yaml and turbo.json presence/absence against fixture directories. - Package-scope tags: Validate that
packages:frontmatter is well-formed when present in spec/roadmap files. Note: the currentmonorepo-validate.shdoes not yet scantasks/roadmap.mdorspecs/*.mdfor these tags — this is a V2 validation expansion. - Disjointness check: Verify that
ownspaths across lanes in a fixture lane-spec are disjoint. - Must-not-edit baseline: Verify that every lane's
must_not_editincludespnpm-lock.yamland root config files.
Fixtures
tests/fixtures/monorepo/pnpm-turbo/— minimal pnpm workspace with Turborepo (2 packages + 1 shared lib).tests/fixtures/monorepo/pnpm-only/— pnpm workspace without Turborepo.tests/fixtures/monorepo/not-monorepo/— single-app project (detection should return "not a monorepo").tests/fixtures/monorepo/lane-specs-valid.json— complete lane-spec fixture.tests/fixtures/monorepo/lane-specs-invalid.json— lane-spec with overlappingownspaths (should fail validation).
Acceptance Criteria
- [ ]
mono-detectcorrectly identifies pnpm workspaces and Turborepo, outputs.agents/monorepo.jsonwith package list and dependency graph. - [ ]
mono-rungenerates lane specs from roadmap execution profiles, runs/mono-guardpre-flight, dispatches parallel worktree agents for package-scoped steps, and runs cross-cutting steps serially. - [ ]
mono-runstops all lanes on any lane failure and preserves worktree state. - [ ]
mono-shipruns package-scoped and transitive-dependent tests/lint/build before delegating to/ship. - [ ]
mono-guardvalidates lane-spec disjointness pre-flight and boundary compliance post-integration. - [ ] Lane-spec artifact follows JSON + Markdown mirror pattern with lifecycle tracking.
- [ ] Package-scope tags work in
tasks/roadmap.mdandspecs/*.mdvia YAML frontmatter. - [ ] Cross-cutting steps always run serially and complete before dependent parallel lanes.
- [ ] Skills defer to
turbo runwhenturbo.jsonis present, fall back topnpm --filterotherwise. - [ ]
--phaseand--pipelineflags work for broader execution beyond step-at-a-time default. - [ ] Mirrored Claude/Codex skill contracts exist for all v1 skills.
- [ ] Script-based validation passes for contracts, lane-spec schema, detection, and boundary checks.
Open Questions
- Turbo cache sharing across worktrees: Do worktree-isolated agents share Turbo's cache, or does each worktree rebuild from scratch? If cache is per-worktree, parallel execution may be slower than expected. Needs empirical testing.
- Lane-spec approval UX in Codex: Codex lacks plan-mode entry from skills. The lane-spec approval step may need a Codex-native pattern (e.g.,
$mono-runpresents lane specs and requires explicitapprovein the next message). mono-guardglobal vs pack: The existing global/mono-guardand the pack'smono-guardoverlap. Should the global skill be deprecated in favor of the pack version, or kept as a standalone pre-flight tool?- Lockfile mutation exception: Cross-cutting serial steps allow lockfile writes. Should there be an explicit approval gate before any lockfile mutation, even in serial mode?
V2 Roadmap
Skills planned for v2 (not in scope for this spec's implementation):
| Skill | Augments | Purpose |
|---|---|---|
mono-roadmap | /roadmap | Auto-tag phases with package scope from code analysis |
mono-plan-phase | /plan-phase | Generate lane specs during phase decomposition |
mono-spec-interview | /spec-interview | Scope-aware spec writing with package boundary prompts |
mono-affected | /affected | Transitive impact analysis with lane-spec integration |
mono-debug | /debug | Package-scoped debugging with cross-package trace |
mono-trace | /trace | Request tracing across package boundaries |
mono-investigate | /investigate | Scoped investigation with package-aware code search |
mono-migrate | (new) | Single-app → monorepo migration with guided execution |
Assumptions & Risks
| Assumption | Source | Downstream Risk if Wrong |
|---|---|---|
| pnpm workspaces + Turborepo is sufficient for v1 | [from interview] Confirmed by user | Projects using npm/yarn/Nx/Lerna cannot use the pack until support is added |
| Root-level specs/research/tasks with package tags is sufficient | [from interview] Confirmed by user | If package isolation is needed later, migrating from root-level tags to per-package directories is a structural change |
| Augmentation injection pattern works without modifying global skills | [inferred] Not yet validated | If global skills don't have clean pre/post hook points, augmentation may require global skill changes |
| Worktree-isolated agents can share Turbo cache | [inferred] Needs empirical testing | If cache is per-worktree, parallel execution loses Turbo's main benefit (caching) |
| Lane-spec JSON + Markdown mirror is worth the complexity | [from interview] User chose this pattern | Maintaining two representations adds sync risk, though the approval-packet precedent suggests it works |
| Stop-all-lanes failure semantics are always correct | [from interview] Confirmed by user | For independent packages, continuing other lanes might be more productive; strict stop may slow development |
| Single-app → monorepo migration is the only migration path needed | [from interview] Confirmed by user | Multi-repo → monorepo and monorepo restructuring are common; deferring may block users with those needs |
| Cross-cutting steps can always be identified by package-scope tags | [inferred] Not yet validated | Some cross-cutting changes (e.g., shared type updates that affect all packages) may not be obvious from tags alone |
mono-detect.sh can reliably build the dependency graph from package.json files | [inferred] Standard approach | Workspace protocol aliases, file: dependencies, and conditional dependencies may produce incorrect graphs |