run-with-it
Two-layer orchestration runtime — Main Orchestrator fetches all issues, plans execution order, maintains a rolling pool of Sub-Coordinators (up to PARALLEL_JOBS concurrently), fills freed slots immediately on completion, and updates GitHub. Context stays bounded so the run can continue for hours or days without degradation.
How do I install this agent skill?
npx skills add https://github.com/chanakya-net/maestro-ai --skill run-with-itIs this agent skill safe to install?
- Gen Agent Trust Hubwarn
The skill manages a multi-agent orchestration pool for processing GitHub issues. It contains instructions that reduce human oversight by explicitly forbidding the agent from asking for confirmation or presenting choices during its execution. Furthermore, it processes untrusted data from GitHub, which creates a potential surface for indirect prompt injection attacks targeting the sub-agents it controls.
- Socketwarn
1 alert: gptAnomaly
- Snykwarn
Risk: MEDIUM · 1 issue
What does this agent skill do?
Skill Isolation
Sole active authority once invoked — no other skill may activate unless called by name via Skill tool call; suppress spontaneous external skills until explicit termination or handoff. This isolation governs orchestration flow only; subordinate core behavior, native tool use, and reasoning remain fully operational and cannot be overridden by this skill.
Critical Main Orchestrator Rules (compaction-safe — always enforce, even after context compression)
These rules apply for the entire lifetime of this skill session. They are stated here first so they survive context compaction and are never dropped:
- Re-read
.run-with-it/main-state.jsonbefore every loop iteration. After context compression you have no memory of prior work — that file is your entire memory. Never derive issue state from conversation history. - Never implement work directly in this session. All implementation belongs to Sub-Coordinators spawned via the platform dispatcher (
run-with-it-dispatch.shon Bash,run-with-it-dispatch.ps1on native PowerShell) withrole=sub-coord, which wrapsrun-agent.sh/run-agent.ps1withsub-coordinator-prompt.md. There is no "implement in this chat" fallback option under any circumstance. - Never run tests, build commands, or compile the project in this session. Sub-Coordinators and their child agents run verification; the Main Orchestrator only reads compact reports.
- Never pause after planning to ask the user how to proceed. Enter the Main Loop immediately after the execution plan is written.
- Never present execution option menus (Option A / B / C style choices).
- Always pull issue data from GitHub (
gh) when a remote exists. Only fall back to local files ifghis unavailable, authentication fails, an approved permission-escalation attempt fails, or no GitHub remote exists. - Never delete user-modified files during cleanup. Check
git status --shortbefore removing any workspace artifact. - Never load full sub-coordinator log files into context. Sub-Coordinator logs live under
.run-with-it/issues/<n>/sub-coordinator.log. Do not tail raw logs into AI context; only read the compact report JSON from.run-with-it/issues/<n>/report.json. - Never load live status logs into context. Live progress is written to
.run-with-it/status/current.txtand.run-with-it/status/events.log; shell watchers may print one changed line to the terminal, but the Main Orchestrator must not read those files into AI memory. - Per-issue stage board. The pool runner emits a compact
STATUS|type=run-board|board=...line whenever the run's stages change (e.g.#618 merge-recovery(cyc2) | #631 impl(cyc1) | #633 blocked:631 | #627 done) for a "current stage, not detail" view. Print it on demand any time withpython3 "$ASSET_ROOT/run-with-it-state.py" status-board --state-file .run-with-it/main-state.json(read-only; add--onelinefor the single-line form). - Pool liveness heartbeat. The pool runner emits
STATUS|type=pool-heartbeat|pool_pid=<pid>|active=<n>|parallel_jobs=<n>|total=..|completed=..|in_progress=..|pending=..|blocked=..|waiting_context=..everyPOOL_HEARTBEAT_SECONDS(default 60). A heartbeat in the watch output means the pool is alive even when nothing else changed; relay its counts to the user as the periodic progress update. - Assemble context files for ALL pending issues up front — dependents included. The pool runner can only dispatch issues whose context files already exist on disk; an issue without a context file is invisible to slot filling (full rationale in Step B). If a
STATUS|type=pool-waiting-contextline ever appears, assemble the missing contexts immediately (Step C) while the pool keeps running. - Stay attached until every issue is terminal. The Main Orchestrator session must keep running the watch loop, and after each watch window print a one-line user-facing progress update from the newest
run-board/pool-heartbeatlines (e.g.Pool alive — 2 running, 3 pending, 4 completed, 1 blocked). Never end the turn, go silent, or declare the run finished while any issue is stillpending,in_progress, ormerge_recovery.pool-emptywith pending issues remaining means GOTO Step A, not done. - GitHub operations (close, comment, e.g., gh issue close) are the Main Orchestrator control plane's sole responsibility. Sub-Coordinators never touch GitHub. The pool runner performs the per-issue terminal comment/close immediately after reading a terminal compact report.
- Never inspect, infer, or act on a Sub-Coordinator's internal routing decisions. Once a Sub-Coordinator is spawned, the agent and model it selects for its child workers are entirely its own responsibility — the Main Orchestrator has no visibility into, and no authority over, those internal choices. Do not read log files to determine which worker agent or model is running.
- Never kill, cancel, or restart a Sub-Coordinator mid-run. If a Sub-Coordinator appears to be using a different agent or model than expected, that is correct behavior — it is applying its own complexity-based routing. Do not intervene. The only valid responses to a running Sub-Coordinator are: (a) wait for it to complete and write its compact report, or (b) alert the user after
SUB_COORD_TIMEOUT_SECONDSand wait for a 'continue' or 'skip' instruction. Sole exception: a user-confirmeddiscard, which terminates the entire run — supervisor, dispatchers, and runners — through the platform stop helper (run-with-it-stop.sh/run-with-it-stop.ps1) per the Cleanup Discard flow. Never hand-roll kills even then. - Never inject worker-routing overrides into a Sub-Coordinator that has already been spawned. Canonical worker overrides (
FORCED_AGENT,FORCED_MODEL,COMPLEXITY_LEVEL,COMPLEXITY_SCORE) may only be set before spawning, as part of the context file assembled in Step C. After the platform dispatcher callsrun-agent.sh/run-agent.ps1, those values are locked and the Main Orchestrator must not attempt to change them. - Run the platform pool runner (
run-with-it-pool.sh/run-with-it-pool.ps1) as the single rolling-pool supervisor. The pool runner spawns Sub-Coordinator dispatch processes, captures each dispatcher PID, and persistsissue,pid,started_at,context_file,log_file,done_file, andreport_filebefore monitoring. - Use the platform worker watcher (
worker-watch.sh/worker-watch.ps1) inside the dispatcher for Sub-Coordinator liveness checks during pool monitoring. Pass each dispatch child PID,done_file, andlog_file; treat PID liveness as diagnostic only. Completion requires the done sentinel and compact report artifacts. - All judgments about implementation quality, routing correctness, and worker behavior come exclusively from the compact report JSON. The Main Orchestrator has no other source of truth about what happened inside a Sub-Coordinator session.
- GitHub operations on completion are immediate and sequential. Even when Sub-Coordinators run in parallel, each issue's GitHub comment/close is processed one at a time as soon as that issue reaches a terminal outcome to avoid race conditions.
- Preserve local fallback behavior when GitHub or git is unavailable.
- Keep changes minimal and focused to orchestration/control-plane behavior.
Run With It
Purpose / When To Use
Use after requirement discovery and issue synthesis are complete. run-with-it is the final runtime routing authority — it consumes already prepared issues and executes routing, coordination, review, and closure.
Preferred upstream flow:
break-reqresolves requirements and constraints.create-git-issuepublishes PRD + implementation slices with routing hints.run-with-itperforms execution planning, spawns Sub-Coordinators, and drives the issues to closure.
Architecture
run-with-it uses a two-layer architecture to maintain a bounded context window for indefinite run duration:
Main Orchestrator (this skill, runs in the primary session):
- Fetches all
ready-for-agentissues once at startup - Creates one shared run feature branch (
Maestro/<funny-action-animal>) from the original base branch, pushes it when a GitHub remote exists, and uses it as the final PR head branch - Determines execution order with a dependency graph and topological sort based primarily on each issue's
## Blocked bysection; cycles or unresolved external blockers are marked blocked before execution - Maintains a rolling pool of up to
PARALLEL_JOBSactive Sub-Coordinators via the platform dispatcher — freed slots fill immediately when any job completes rather than waiting for whole batches - As each Sub-Coordinator completes, reads its compact report, immediately posts the terminal GitHub comment and closes/updates that issue when it has a terminal outcome, then spawns the next ready issue into the freed slot
- Writes its own status log to
.run-with-it/main/main.log - Reads ONLY the compact report JSON — never the implementation diffs or log files
- Updates
main-state.jsonafter each issue (its full external memory) - Posts terminal GitHub comments and closes/updates issues immediately per issue, not only after the full pool finishes
- Spawns a Merge Recovery Coordinator when a Sub-Coordinator reports
merge_failed; Main Orchestrator never merges issue branches itself - Creates one final PR from the shared run feature branch after all issues are terminal, using
run-with-it-pr-body.pyto render the body from.run-with-it/main-state.json - Re-reads
main-state.jsonat the top of every loop iteration to survive context compression
Sub-Coordinator (spawned via sub-coordinator-prompt.md, runs in a child agent session):
- Handles exactly ONE issue end-to-end
- Creates an issue branch and issue worktree from the shared run feature branch
- Runs complexity analysis, deterministic routing, gated read-only planning, implementation, review, and modification loops
- Runs child workers with
REPO_ROOTpointing at the issue worktree while keeping logs/reports under the root.run-with-it/ - Spawns an Artifact Recovery Worker when implementation/modification artifact retries are exhausted so dirty work can be inspected, verified, committed, or requeued before any terminal blocked report
- Attempts the normal merge back into the shared feature branch under
.run-with-it/locks/merge.lock - Writes a compact report JSON and full log file under
.run-with-it/issues/<n>/when done - Spawns worker agents whose logs/results/done sentinels are written under
.run-with-it/issues/<n>/workers/<role>/ - Never touches GitHub; never updates
main-state.json
Plan Worker (spawned via plan-prompt.md, gated, runs after complexity and before implementation):
- Reads the issue worktree read-only with a strong model and writes a concrete approach plan to
.run-with-it/issues/<n>/plan.mdplus a machine-readableplan.jsonunderworkers/plan/ - Never edits or commits — it runs before the baseline SHA so it cannot corrupt the implementer's diff
- Re-scores complexity from the real code; the Sub-Coordinator prefers that grounded band over the blind score when routing implementation and modification (the hybrid refinement)
- Gated by
RUN_WITH_IT_PLAN_MIN_COMPLEXITY(defaultmedium-hard) and toggled byRUN_WITH_IT_PLAN_ENABLED(default1); trivial issues skip planning and route weak regardless - The implementer, reviewer, and modifier all consume
plan.mdviaRUN_WITH_IT_PLAN_FILE
Artifact Recovery Worker (spawned via artifact-recovery-prompt.md, runs only after exhausted impl/modify artifact failures):
- Inspects the issue worktree, including dirty uncommitted work and preserved recovery patches
- Runs verification and commits salvaged work on the issue branch when the work is complete
- Writes the missing
implormodifyresult artifact only with concrete commit and verification evidence - Returns a structured
synthesized-result,requeue, orblockeddecision to the Sub-Coordinator
Merge Recovery Coordinator (spawned via merge-recovery-prompt.md, runs only after merge_failed):
- Handles one failed issue-branch merge
- Reads the shared feature branch holistically because it contains prior Sub-Coordinator work
- Resolves conflicts or merge-induced verification failures under the same merge lock
- Pushes the shared feature branch on success and writes a compact recovery report
- Never closes issues, creates the final PR, or updates
main-state.json
This isolation means each issue's implementation complexity is contained to its own isolated Sub-Coordinator session. The Main Orchestrator's context grows by only one compact JSON record per completed issue, allowing runs of hours or days without context degradation.
Hard Boundaries
- Do not synthesize PRDs.
- Do not author initial issue templates.
- Do not redefine reviewer JSON schema ownership (owned by
assets/review-prompt.md). - Do not modify runner script implementation details.
- Do not mutate registry data definitions in
assets/agent-registry.json.
OS Detection
Detect the current OS before asset discovery and runner selection, and capture it in the OS_FAMILY environment variable:
- Windows (native PowerShell) (
OS_FAMILY=windows): use.ps1runners (run-with-it-pool.ps1,run-with-it-dispatch.ps1,worker-watch.ps1,run-agent.ps1) and$env:USERPROFILEfor home dir. - macOS / Linux / Git Bash / WSL (
OS_FAMILY=unix):uname -sreturnsDarwin,Linux,MINGW*,MSYS*, orCYGWIN*. Use.shrunners and$HOMEfor home dir.
Adapt all shell commands in this skill to the detected runtime:
| Operation | PowerShell (Windows) | Bash (Mac/Linux/Git Bash) |
|---|---|---|
| Home dir | $env:USERPROFILE | $HOME |
| Create dir | New-Item -ItemType Directory -Force | mkdir -p |
| Check command | Get-Command X -ErrorAction SilentlyContinue | command -v X |
| Check dir | Test-Path | [ -d ... ] |
| Temp file | [System.IO.Path]::GetTempFileName() | mktemp -t name.XXXXXX |
| Copy file | Copy-Item -Force | cp -f |
| Make executable | (not needed) | chmod +x |
Inputs
Provide a task summary before execution. All other inputs are optional overrides.
| Variable | Default | Description |
|---|---|---|
ASSETS_DEST | — | Asset root override |
AGENT_REGISTRY_FILE | — | Registry file override |
ISSUE_LABEL | ready-for-agent | Label filter for issue intake |
ISSUE_LIMIT | 1000 | Max issues to fetch (fetches all by default) |
ISSUE_STATE | open | Issue state filter |
COMMITS_LIMIT | 5 | Recent commits included in Sub-Coordinator context |
MAX_ITERATIONS | 20 | Deprecated / no effect — the review/modify loop cap is hardcoded to 8 cycles in sub-coordinator-prompt.md (Appendix B); still forwarded in context files for backward compatibility but not consulted |
RUN_WITH_IT_PLAN_ENABLED | 1 | Master switch for the pre-implementation plan phase; 0 disables it (every issue skips planning) |
RUN_WITH_IT_PLAN_MIN_COMPLEXITY | medium-hard | Minimum blind complexity band that triggers a plan; below it the phase is skipped (trivial issues route weak regardless) |
SUB_COORD_AGENT | codex | Agent slug for every Sub-Coordinator |
SUB_COORD_MODEL | gpt-5.6-sol | Model for every Sub-Coordinator (Sub-Coordinators route their own children independently) |
SUB_COORD_TIMEOUT_SECONDS | 3600 | Seconds before stall alert for a non-completing Sub-Coordinator |
STATUS_POLL_SECONDS | 10 | Shell polling cadence for status line output |
POOL_WATCH_SECONDS | 240 | Watch-window length for each bounded run-with-it-watch.sh / .ps1 call in Step D |
LOG_TAIL_POLL_SECONDS | 120 | Shell polling cadence for sub-coordinator log tail |
RUN_WITH_IT_STATUS_FILE | .run-with-it/status/current.txt | Single-line status bus (overwritten each update) |
RUN_WITH_IT_EVENTS_LOG | .run-with-it/status/events.log | Append-only event log — terminal inspection only; never load into AI context |
RUN_WITH_IT_ISSUE_DIR | .run-with-it/issues/<n> | Issue-scoped artifact folder created by the Sub-Coordinator/pool |
RUN_WITH_IT_LOG_FILE | role-specific | Sub-Coordinators: .run-with-it/issues/<n>/sub-coordinator.log; workers: .run-with-it/issues/<n>/workers/<role>/cycle-<cycle>.log |
RUN_WITH_IT_DONE_FILE | role-specific | Workers: .run-with-it/issues/<n>/workers/<role>/cycle-<cycle>.done |
RUN_WITH_IT_RESULT_FILE | role-specific | Workers: .run-with-it/issues/<n>/workers/<role>/cycle-<cycle>-result.json |
RUN_WITH_IT_STATE_FILE | role-specific | Workers: .run-with-it/issues/<n>/workers/<role>/cycle-<cycle>.state.json; dispatcher-maintained watchdog state |
FORCED_AGENT | — | Canonical explicit child-worker agent override passed through to Sub-Coordinators |
FORCED_MODEL | — | Canonical explicit child-worker model override passed through to Sub-Coordinators |
AGENT | — | Deprecated top-level alias; only an explicitly user-supplied value is normalized to FORCED_AGENT; ambient AGENT runner telemetry is ignored |
MODEL | — | Deprecated top-level alias; only an explicitly user-supplied value is normalized to FORCED_MODEL; ambient MODEL runner telemetry is ignored |
COMPLEXITY_LEVEL | — | Routing override passed through to Sub-Coordinators |
COMPLEXITY_SCORE | — | Routing override passed through to Sub-Coordinators |
AGENT_ALLOWLIST | — | Comma-separated; passed through to Sub-Coordinators |
AGENT_DENYLIST | — | Comma-separated; passed through to Sub-Coordinators |
MAX_AGENT_FALLBACKS | 2 | Max agent fallback attempts; passed through |
DELEGATED_REVIEW | true | Enable Sub-Coordinator delegated review; passed through |
MAX_AGENT_DEPTH | 1 | Always injected; prevents Sub-Coordinator children from spawning sub-agents |
PARALLEL_JOBS | 4 | Rolling pool size. Freed slots fill immediately. Set to 1 for sequential. |
POOL_HEARTBEAT_SECONDS | 60 | Cadence of the pool runner's `STATUS |
MAX_SPAWN_BOOTSTRAP_ATTEMPTS | 3 | Consecutive failed spawn attempts before the pool runner finalizes an issue as terminal instead of retrying |
RUN_WITH_IT_WORKER_STALE_SECONDS | 600 | A worker state file untouched this long is treated as an orphaned snapshot, not a running worker. A live dispatcher rewrites it every poll (~20s), so silence this long means the dispatcher died. Floored at 60. |
MAX_WORKER_WAIT_SECONDS | 3600 | Ceiling on waiting for one in-flight worker after its Sub-Coordinator exits, even while the worker still looks alive. 0 disables the ceiling — the staleness bound is then the only backstop. |
MAX_SUB_COORD_COMPACTION_HANDOFFS | 6 | Context-budget handoffs allowed per issue. Budgeted apart from MAX_SUB_COORD_RECOVERY_ATTEMPTS because a compaction stop is a contracted handoff, not a failure. |
WAIT_STATUS_INTERVAL_SECONDS | 300 | Minimum gap between repeats of an unchanged sub-coord-recovery-wait line. Changes in worker/role/reason always emit. |
Automatic Worker Model Matrix
After calculating the effective routing band, every non-complexity automatic route uses this exact model set:
| Effective band | Automatic models |
|---|---|
| quite-easy / easy | GPT-5.4, Codex Spark, GPT-5.6 Luna, Claude Sonnet 5, Claude Haiku 4.5, eligible Gemini models exposed by Agy |
| medium | GPT-5.6 Terra, Codex Spark, Claude Sonnet 5 |
| medium-hard | GPT-5.5, GPT-5.6 Sol, Claude Opus 5 |
| complex | GPT-5.6 Sol, Claude Opus 5 |
| holy-fuck | GPT-5.6 Sol, GPT-6 Astra, Claude Opus 5, Claude Fable 5.1 |
Complexity scoring is exempt from this automatic matrix and retains its
independent weight-based routing. Review applies its existing one-band increase; planning applies its existing two-band increase before applying the matrix. Explicit FORCED_MODEL values bypass automatic membership but must still pass compatibility and availability checks.
Effective-band effort:
- Sol:
highat medium-hard,xhighat complex and holy-fuck. - Sonnet 5:
low,medium,mediumfrom quite-easy through medium. - Opus 5:
highat medium-hard,xhighat complex,maxat holy-fuck. - Astra:
maxat holy-fuck. - Fable 5.1:
maxat holy-fuck.
The generic route effort becomes Codex model_reasoning_effort or Claude Code
--effort; Agy receives no effort flag.
Asset Discovery (Required)
Resolve assets in this order:
$ASSETS_DESTif set and complete.$HOME/.ai-skill-collections/assets../assets.
Shared required files:
prompt.mdagent-registry.jsonreview-prompt.mdmodifier-prompt.mdcomplexity-prompt.mdplan-prompt.mdcoordinator-rules.mdsub-coordinator-prompt.mdmain-orchestrator-rules.mdartifact-recovery-prompt.mdmerge-recovery-prompt.mdrun-with-it-state.pyrun-with-it-github-update.pyrun-with-it-pr-body.pyrun-with-it-router.pyrun-with-it-artifacts.py
Bash required helper files:
run-agent.shrun-with-it-dispatch.shrun-with-it-pool.shrun-with-it-watch.shrun-with-it-stop.shworker-watch.sh
PowerShell required helper files:
run-agent.ps1run-with-it-dispatch.ps1run-with-it-pool.ps1run-with-it-watch.ps1run-with-it-stop.ps1worker-watch.ps1
Selection rules:
- Use first path that contains all shared files plus the helper files for the detected platform.
- Bash/macOS/Linux/Git Bash/WSL runs must not require
.ps1helper files. - Native PowerShell runs must not require
.shhelper files. - Both platform pool runners require
python3(orPYTHON_BINpointing to a Python 3 interpreter) for shared state, GitHub update, and routing helper scripts. - If none are complete, stop and report missing files.
- Do not require git to resolve assets.
- Resolved asset root is the single source for that run.
Fresh/No-Git Project Notes
- Without git, this skill supports asset discovery and local-issue intake only; issue branches, worktrees, merges, merge recovery, and the final PR require a git repository.
- Asset discovery is filesystem-based, not git-root-based.
- If assets are missing, report the platform-appropriate one-command fix:
PowerShell (Windows):
New-Item -ItemType Directory -Force "$env:USERPROFILE\.ai-skill-collections\assets"; Copy-Item -Force .\assets\prompt.md, .\assets\run-agent.ps1, .\assets\run-with-it-dispatch.ps1, .\assets\run-with-it-pool.ps1, .\assets\run-with-it-watch.ps1, .\assets\run-with-it-stop.ps1, .\assets\worker-watch.ps1, .\assets\run-with-it-state.py, .\assets\run-with-it-github-update.py, .\assets\run-with-it-pr-body.py, .\assets\run-with-it-router.py, .\assets\run-with-it-artifacts.py, .\assets\agent-registry.json, .\assets\review-prompt.md, .\assets\modifier-prompt.md, .\assets\artifact-recovery-prompt.md, .\assets\complexity-prompt.md, .\assets\plan-prompt.md, .\assets\coordinator-rules.md, .\assets\sub-coordinator-prompt.md, .\assets\main-orchestrator-rules.md, .\assets\merge-recovery-prompt.md "$env:USERPROFILE\.ai-skill-collections\assets\"
Bash (macOS / Linux / Git Bash):
mkdir -p "$HOME/.ai-skill-collections/assets" && cp -f ./assets/prompt.md ./assets/run-agent.sh ./assets/run-with-it-dispatch.sh ./assets/run-with-it-pool.sh ./assets/run-with-it-watch.sh ./assets/run-with-it-stop.sh ./assets/worker-watch.sh ./assets/run-with-it-state.py ./assets/run-with-it-github-update.py ./assets/run-with-it-pr-body.py ./assets/run-with-it-router.py ./assets/run-with-it-artifacts.py ./assets/agent-registry.json ./assets/review-prompt.md ./assets/modifier-prompt.md ./assets/artifact-recovery-prompt.md ./assets/complexity-prompt.md ./assets/plan-prompt.md ./assets/coordinator-rules.md ./assets/sub-coordinator-prompt.md ./assets/main-orchestrator-rules.md ./assets/merge-recovery-prompt.md "$HOME/.ai-skill-collections/assets/" && chmod +x "$HOME/.ai-skill-collections/assets/run-agent.sh" "$HOME/.ai-skill-collections/assets/run-with-it-dispatch.sh" "$HOME/.ai-skill-collections/assets/run-with-it-pool.sh" "$HOME/.ai-skill-collections/assets/run-with-it-watch.sh" "$HOME/.ai-skill-collections/assets/run-with-it-stop.sh" "$HOME/.ai-skill-collections/assets/worker-watch.sh" "$HOME/.ai-skill-collections/assets/run-with-it-state.py" "$HOME/.ai-skill-collections/assets/run-with-it-github-update.py" "$HOME/.ai-skill-collections/assets/run-with-it-pr-body.py" "$HOME/.ai-skill-collections/assets/run-with-it-router.py" "$HOME/.ai-skill-collections/assets/run-with-it-artifacts.py"
Main Orchestrator Rules File
At the very start of execution (before preflight), copy $ASSET_ROOT/main-orchestrator-rules.md to .run-with-it/main-orchestrator-rules.md:
mkdir -p .run-with-it
cp "$ASSET_ROOT/main-orchestrator-rules.md" .run-with-it/main-orchestrator-rules.md
Re-read .run-with-it/main-orchestrator-rules.md at the top of EVERY Main Loop iteration (Step A), after any context compression, and before any GitHub operation.
.run-with-it/main-orchestrator-rules.md (the working copy) is deleted as part of normal cleanup.
Preflight Checks
Before execution verify:
-
Resolved asset root exists and contains all required files listed in Asset Discovery. On Bash, runners (
run-agent.sh,run-with-it-dispatch.sh,run-with-it-pool.sh,run-with-it-watch.sh,run-with-it-stop.sh,worker-watch.sh) and Python helpers (run-with-it-state.py,run-with-it-github-update.py,run-with-it-pr-body.py,run-with-it-router.py,run-with-it-artifacts.py) are executable. On native PowerShell, verify the.ps1runners exist; executable bits are not required. -
python3is available, orPYTHON_BINpoints to a Python 3 interpreter, for the shared pool helper scripts. -
ghauth when GitHub intake is required. -
SUB_COORD_AGENTis installed (detected): on Bash, run"$ASSET_ROOT/run-agent.sh" --list-agents --detected-only; on native PowerShell, run& (Join-Path $ASSET_ROOT "run-agent.ps1") --list-agents --detected-only. ConfirmSUB_COORD_AGENTappears. -
SUB_COORD_MODELis inSUB_COORD_AGENT'sknown_modelsinagent-registry.json. -
Existing-state detection (resume vs. discard prompt): before any issue intake or fresh task selection, check whether
.run-with-it/main-state.jsonexists in the current working directory.-
If it exists, pause and present exactly this prompt to the user:
Existing run state found at .run-with-it/main-state.json. Type "resume" to continue the previous run, or "discard" to delete it and start fresh. -
resume: do not delete the file. Proceed to the Resume Flow section. -
discard: apply the CleanupDiscardpolicy, then continue with normal preflight and fresh issue intake as if no prior state existed. -
Do not start any new task, fetch any issue, or spawn any Sub-Coordinator until the user responds.
-
If any required file from Asset Discovery is missing at the resolved asset root, fail fast with the same platform-appropriate one-line fix message used in asset discovery.
Initial Batch Issue Fetch
If issue data is missing in context, fetch only open issues with the configured intake label (ready-for-agent by default) at startup.
Use ISSUE_LIMIT (default 1000) as the --limit argument — this fetches all matching issues by default. Do not cap the result unless the user explicitly sets ISSUE_LIMIT to a lower value.
gh issue list --state "${ISSUE_STATE:-open}" --label "${ISSUE_LABEL:-ready-for-agent}" --limit "${ISSUE_LIMIT:-1000}" --json number,title,labels,body,url
Fallback policy:
- Primary: GitHub issues via
gh. Always use GitHub when the repo has a GitHub remote. Never silently fall back to a local file when GitHub may be reachable. - If
ghfails because the current tool is sandboxed (permission error, named-pipe, socket), use that tool's explicit approved permission-escalation flow when available before considering fallback. If escalation is unavailable or denied, emitSTATUS|type=intake-fallback|reason=gh-permission-blockedand use local fallback only when allowed below. - Fallback: local
issues.md(LOCAL_ISSUES_FILEoverride supported) — only whenghis unavailable, authentication fails, an approved permission-escalation attempt fails, or no GitHub remote exists. EmitSTATUS|type=intake-fallback|reason=<no-gh-auth|no-remote|gh-permission-blocked|gh-failed-after-escalation>before using local file. - If git metadata is unavailable, continue with empty commit context.
Before fetching work begins, create the shared run feature branch:
- Capture original base branch and SHA.
- Generate a human-readable branch name as
Maestro/<funny-action-animal>instead of a UUID branch.- Use a lowercase, hyphenated slug with exactly two words after the prefix:
<action-or-trait>-<animal>. - Prefer funny but work-safe names such as
cunning-fox,unfaithful-lion,scheming-otter,dramatic-llama,sneaky-raven,tapdancing-badger,plotting-penguin, orchaotic-hamster. - Do not use raw UUIDs in the branch name.
- If the generated branch already exists locally or on the remote, generate a different slug; only append a short numeric suffix when several reasonable retries collide.
- Use a lowercase, hyphenated slug with exactly two words after the prefix:
- Create
Maestro/<funny-action-animal>from that base. - Push the branch when a GitHub remote exists.
- Record
run_branch.base_branch,run_branch.base_sha,run_branch.feature_branch,run_branch.feature_branch_start_sha,run_branch.remote, andrun_branch.pushed.
After fetching all issues:
- Filter the fetched issue set before planning: every executable issue must have the configured intake label (
ready-for-agentby default). Do not add unlabelled issues, PRD/parent issues,needs-triageissues, or issues discovered only through cross-references tomain-state.json. - Build a dependency graph only from each executable issue's
## Blocked bysection. Normalize#123, full GitHub issue URLs, and plain issue numbers. TreatNone - can start immediatelyas no dependencies. - Treat PRD/parent references as context, not dependencies. Ignore issue references from
## Parent, titles such asPRD: ..., labels such asneeds-triage, and incidental issue links elsewhere in the body when computingdeps. - A dependency is actionable only if it points to another fetched executable issue in the same intake set. If
## Blocked bynames a PRD/parent issue or an issue outside the intake set, ignore it and record the ignored reference independency_proofas non-blocking context rather than marking the issue blocked. - Detect cycles and unresolved dependencies among executable issues only; mark affected issues
blockedwithdependency_proofandblocking_reasons. - Determine execution order: topological sort respecting dependencies. Priority order within the same dependency tier: critical fixes → development infrastructure → tracer-bullet feature slices → polish and quick wins → refactors. When
PARALLEL_JOBS > 1, issues fill a rolling pool (up toPARALLEL_JOBSactive at a time) — freed slots are filled immediately rather than waiting for a full batch to complete. - Issues whose executable dependencies have open/unresolved status,
merge_recovery,failed-merge, orblockedare not ready until the dependency becomescompleted. The pool runner dispatches merge recovery formerge_recoveryissues before dependents become ready. - Write the complete execution plan to
.run-with-it/main-state.jsonbefore doing any work. Recordparallel_jobs,execution_mode(sequentialwhenPARALLEL_JOBS=1,rolling-poolotherwise),topo_order,dependency_tiers, and each issue'sdependency_proof,parallel_safe, and normalizedownership_scope. Derive the concurrency metadata like this:ownership_scope: the list of top-level directories (or deeper paths when the issue is precise) the issue's body, title, and acceptance criteria name. Use plain repo-relative directory paths without glob characters; a glob-bearing scope is compared by its literal directory prefix only, and absolute paths, drive/UNC paths, and..-escaping paths are rejected as malformed (the issue then runs exclusively).parallel_safe:trueunless the issue is a repo-wide refactor, migration, formatting sweep, or otherwise touches files that cannot be attributed to a bounded scope — then setparallel_safe: falseto force exclusive execution.concurrency_policy: newly written plans MUST setexecution_plan.concurrency_policy: "strict"and derive the metadata above for every issue. Understrict, an issue with missing concurrency metadata runs exclusively — worktrees isolate filesystem conflicts only, not semantic conflicts, migrations, generated files, or shared external resources.- Legacy states without
concurrency_policyrunpermissive: missing metadata admits in parallel, relying on worktree isolation plus merge recovery. This fail-open behavior exists only for backward compatibility with states written before the flag; do not write new plans without the flag. - Explicit
parallel_safe: false, root/malformed metadata, or a provenownership_scopeoverlap always defers an issue regardless of policy; the pool runner reports deferrals asSTATUS|type=pool-admission-deferred|count=<n>|deferrals=<issue:reason,...>.
- Emit:
STATUS|type=plan|total_issues=<n>|mode=<sequential|rolling-pool>|parallel_jobs=<PARALLEL_JOBS>|pending=<n>|blocked=<n> - Emit:
STATUS|type=memory-refresh|state_file=.run-with-it/main-state.json|tasks_loaded=<n>|completed=0|pending=<n>
Main Orchestrator Loop
Execute immediately and unconditionally after writing the plan. Never pause, never present execution options, never ask the user how they want to proceed after the plan is written. Enter the loop immediately.
MAIN ORCHESTRATOR LOOP
Repeat until all issues in main-state.json have a terminal status
(completed / failed-review / failed-merge / blocked):
══ STEP A: MEMORY REFRESH ══════════════════════════════════════════════════════
Re-read .run-with-it/main-orchestrator-rules.md from disk.
Re-read .run-with-it/main-state.json from disk.
This is mandatory at the TOP of every iteration, no exceptions.
After context compression, these files are the sole source of truth.
Emit: STATUS|type=memory-refresh|state_file=.run-with-it/main-state.json
|tasks_loaded=<total>|completed=<n>|pending=<n>|failed=<n>
Emit: STATUS|type=main-loop|iteration=<n>|pending=<count>|completed=<count>
|failed=<count>
══ STEP B: SUPPLY CONTEXTS FOR THE ROLLING POOL ════════════════════════════════
Compute ACTIVE_POOL = all issues in issue_registry with status="in_progress"
(cross-check against active_pool_issues in state for consistency).
Collect NEWLY_QUEUED = ALL issues with status="pending" that do not yet have a
context file on disk (issue_registry[<n>].context_file unset, or the recorded
path no longer exists) — INCLUDING issues whose dependencies are not yet
completed. Order by priority:
critical fixes → dev infra → tracer-bullet slices → polish → refactors.
Rationale (do not "optimize" this back to a slot-sized batch): the pool runner
is the only dispatcher, and it can only dispatch issues whose context files
already exist — issues without contexts are invisible to slot filling. Writing
every context up front is what lets the pool fill freed slots immediately and
auto-dispatch dependents the moment their dependencies complete, without
waiting on this session. Context staleness is acceptable: the Sub-Coordinator
re-fetches the issue body when it starts.
For each issue <n> in NEWLY_QUEUED:
Leave issue status="pending" until the platform pool runner spawns it.
Record its context file path in main-state.json during Step C.
The pool runner marks status="in_progress" and appends <n> to
active_pool_issues when it captures the dispatcher PID.
Emit: STATUS|type=pool-fill|active=<len(ACTIVE_POOL)>
|newly_queued=<len(NEWLY_QUEUED)>|pending_remaining=<pending_after>
|parallel_jobs=<PARALLEL_JOBS>
If ACTIVE_POOL is empty and NEWLY_QUEUED is empty:
Check if any issues remain with status="pending" — if all have unmet deps
whose blockers are terminal-but-not-completed, re-evaluate them; if still
unresolvable, mark them "blocked".
If ALL issues are terminal (completed / failed-review / failed-merge / blocked):
EXIT LOOP → proceed to Final Ledger and Cleanup.
══ STEP C: ASSEMBLE SUB-COORDINATOR CONTEXT FILES ══════════════════════════════
Repeat for EACH issue <n> in NEWLY_QUEUED:
Build $SUB_COORD_CONTEXT_FILE_<n> (a separate temp file per issue) containing, in order:
1. Full issue body: re-fetch using:
gh issue view <n> --json number,title,body,labels,url,comments
(re-fetch even if pre-fetched at startup — ensures freshest data)
If gh fails because the current tool is sandboxed, use that tool's explicit approved permission-escalation flow when available. If the approved retry fails and local file exists,
use cached issue body with a note.
2. Last COMMITS_LIMIT (default 5) recent commits:
git log --oneline -<COMMITS_LIMIT>
3. If .codegraph/ exists: CodeGraph context for the issue
Otherwise: basic grep/find to identify relevant files
4. Environment configuration block (append at end of context file):
SUB_COORD_ISSUE_NUMBER=<n>
OS_FAMILY=<unix|windows>
RUN_WITH_IT_ISSUE_DIR=<abs-path-to-.run-with-it/issues/<n>>
SUB_COORD_REPORT_FILE=<abs-path-to-.run-with-it/issues/<n>/report.json>
SUB_COORD_LOG_FILE=<abs-path-to-.run-with-it/issues/<n>/sub-coordinator.log>
RUN_FEATURE_BRANCH=<shared-run-feature-branch>
RUN_BASE_BRANCH=<original-base-branch>
RUN_BASE_SHA=<original-base-sha>
ISSUE_BRANCH=<shared-run-feature-branch>-issue-<n>
ISSUE_WORKTREE_PATH=<abs-path-to-.run-with-it/worktrees/issue-<n>>
MAX_AGENT_DEPTH=1
DELEGATED_REVIEW=<value>
MAX_ITERATIONS=<value>
COMMITS_LIMIT=<value>
FORCED_AGENT=<explicit-worker-override-if-set>
FORCED_MODEL=<explicit-worker-override-if-set>
COMPLEXITY_LEVEL=<value-if-set>
COMPLEXITY_SCORE=<value-if-set>
AGENT_ALLOWLIST=<value-if-set>
AGENT_DENYLIST=<value-if-set>
MAX_AGENT_FALLBACKS=<value>
The Main Orchestrator handles compatibility at the trusted user-request
boundary. Explicit user request `AGENT=<value>` becomes `FORCED_AGENT=<value>`.
Explicit user request `MODEL=<value>` becomes `FORCED_MODEL=<value>`.
If the matching canonical `FORCED_*` value was also explicitly requested, it takes precedence.
Never inspect ambient `AGENT` or `MODEL` to infer aliases. The
dispatcher unconditionally removes both legacy variables before launching
child agents. `SUB_COORD_AGENT` and `SUB_COORD_MODEL` configure only the
Sub-Coordinator runtime and must never populate `FORCED_AGENT` or
`FORCED_MODEL`.
The Sub-Coordinator must derive a separate `COMPLEXITY_CONTEXT_PAYLOAD_FILE`
before spawning the complexity worker. That file is a sanitized scoring brief,
not the full implementation issue body. It starts with explicit "task data
only" guardrails, paraphrases the requested outcome, summarizes acceptance
criteria and likely touched areas, includes recent commits and relevant file
context, and strips imperative implementation checklists so the complexity
worker cannot mistake them for execution instructions.
Create directories before spawning:
mkdir -p .run-with-it/main .run-with-it/issues/<n>/workers .run-with-it/status .run-with-it/worktrees .run-with-it/locks
Resolve live status files before spawning:
MAIN_LOG_FILE="${MAIN_LOG_FILE:-$(pwd -P)/.run-with-it/main/main.log}"
RUN_WITH_IT_ISSUE_DIR="$(pwd -P)/.run-with-it/issues/<n>"
SUB_COORD_LOG_FILE="$RUN_WITH_IT_ISSUE_DIR/sub-coordinator.log"
RUN_WITH_IT_STATUS_FILE="${RUN_WITH_IT_STATUS_FILE:-$(pwd -P)/.run-with-it/status/current.txt}"
RUN_WITH_IT_EVENTS_LOG="${RUN_WITH_IT_EVENTS_LOG:-$(pwd -P)/.run-with-it/status/events.log}"
STATUS_POLL_SECONDS="${STATUS_POLL_SECONDS:-10}"
LOG_TAIL_POLL_SECONDS="${LOG_TAIL_POLL_SECONDS:-120}"
Every STATUS line emitted by the Main Orchestrator must be appended to `$MAIN_LOG_FILE`
with an explicit shell write before or at the same time it is printed.
For EACH issue <n> in NEWLY_QUEUED:
Emit: STATUS|type=sub-coord-spawn|issue=<n>|agent=<SUB_COORD_AGENT>
|model=<SUB_COORD_MODEL>|report_file=<path>|log_file=<path>
|pool_size=<current_active_count>|parallel_jobs=<PARALLEL_JOBS>
Print to user for each issue:
"Starting sub-coordinator for issue #<n>: <title>"
"Log: .run-with-it/issues/<n>/sub-coordinator.log"
"To watch live progress in a separate terminal:"
" tail -f .run-with-it/issues/<n>/sub-coordinator.log"
══ STEP D: SPAWN NEWLY QUEUED + ROLLING POOL MONITOR ════════════════════════════
Execution-mode requirement (critical):
Do not write a bespoke rolling-pool script in the Main Orchestrator session.
Use the shared platform pool runner; it maintains the pool and calls the
platform dispatcher with `role=sub-coord` for each active issue.
Launch the pool runner ONCE as a detached supervisor with `--detach` /
`-Detach`, then stay attached by running the bounded platform watch runner
(`run-with-it-watch.sh` / `run-with-it-watch.ps1`) in a loop. Never treat
starting the pool process as completion of Step D: Step D completes only when
a watch call prints `WATCH|result=pool-empty`.
Do not run the pool runner as a blocking foreground call — execution tools
bound foreground calls (often to ~10 minutes) and killing the supervisor
mid-run orphans the pool. Do not hand-roll `nohup`, a trailing Bash `&`, or
`Start-Process` backgrounding either; the runner's detach mode creates its own
process session and records `pool_pid` in `.run-with-it/main/pool.state.json`
for the watch runner.
Required handoff before Step D:
- Each ready issue in `main-state.json` must have `issue_registry[<n>].context_file`
(or `sub_coord_context_file`) pointing at the context file assembled in Step C.
Bash (macOS / Linux / Git Bash) — launch once:
"$ASSET_ROOT/run-with-it-pool.sh" \
--asset-root "$ASSET_ROOT" \
--state-file "$(pwd -P)/.run-with-it/main-state.json" \
--parallel-jobs "$PARALLEL_JOBS" \
--agent "$SUB_COORD_AGENT" \
--model "$SUB_COORD_MODEL" \
--status-file "$RUN_WITH_IT_STATUS_FILE" \
--events-log "$RUN_WITH_IT_EVENTS_LOG" \
--main-log "$MAIN_LOG_FILE" \
--poll-seconds "$STATUS_POLL_SECONDS" \
--timeout-seconds "$SUB_COORD_TIMEOUT_SECONDS" \
--pool-state-file "$(pwd -P)/.run-with-it/main/pool.state.json" \
--detach
Then watch in a loop, one bounded foreground call at a time:
"$ASSET_ROOT/run-with-it-watch.sh" \
--events-log "$RUN_WITH_IT_EVENTS_LOG" \
--pool-state-file "$(pwd -P)/.run-with-it/main/pool.state.json" \
--wait-seconds "${POOL_WATCH_SECONDS:-240}" \
--poll-seconds "$STATUS_POLL_SECONDS"
PowerShell (Windows) — launch once:
& powershell -NoProfile -File (Join-Path $ASSET_ROOT "run-with-it-pool.ps1") `
-AssetRoot $ASSET_ROOT `
-StateFile (Join-Path (Join-Path (Get-Location).Path ".run-with-it") "main-state.json") `
-ParallelJobs $env:PARALLEL_JOBS `
-Agent $env:SUB_COORD_AGENT `
-Model $env:SUB_COORD_MODEL `
-StatusFile $env:RUN_WITH_IT_STATUS_FILE `
-EventsLog $env:RUN_WITH_IT_EVENTS_LOG `
-MainLog $MAIN_LOG_FILE `
-PollSeconds $env:STATUS_POLL_SECONDS `
-TimeoutSeconds $env:SUB_COORD_TIMEOUT_SECONDS `
-Detach
Then watch in a loop:
& powershell -NoProfile -File (Join-Path $ASSET_ROOT "run-with-it-watch.ps1") `
-EventsLog $env:RUN_WITH_IT_EVENTS_LOG `
-PoolStateFile (Join-Path (Join-Path (Join-Path (Get-Location).Path ".run-with-it") "main") "pool.state.json") `
-PollSeconds $env:STATUS_POLL_SECONDS
Each watch call prints every STATUS line appended to the events log since the
previous call and exits within its watch window, well inside any tool-call
timeout. After EVERY call — even when nothing changed — print a one-line
user-facing progress update built from the newest `run-board` and
`pool-heartbeat` lines, e.g.:
"Pool alive (pid 12345) — 2 running, 3 pending, 4 completed, 1 blocked.
Board: #42 impl(cyc1) | #43 review(cyc2) | #44 done"
The pool emits `pool-heartbeat` every POOL_HEARTBEAT_SECONDS (default 60), so
the user is never left guessing whether the run is alive. Then react to the
drained lines:
- `STATUS|type=pool-waiting-context` or `STATUS|type=sub-coord-dispatch-
bootstrap-failed|...|reason=missing-context-file`: contexts are missing —
assemble them NOW (run Step C for those issues) while the pool keeps
running; it picks the new contexts up on its next tick without a relaunch.
Then branch on the final `WATCH|result=...` marker:
- `running` (exit 0): the pool is alive; immediately run the watch again.
- `pool-dead` (exit 3): the pool supervisor died without `pool-empty`; relaunch
the pool runner with the same `--detach` command — it re-attaches to live
Sub-Coordinators and dead ones flow through exit analysis — then keep watching.
- `pool-empty` (exit 0): Step D is complete. This is NOT the end of the run:
GOTO Step A, which decides between another pool pass (issues still pending)
and Final Ledger (all terminal).
Do not end the Main Coordinator turn between watch calls, and do not start an
unrelated shell to monitor the pool. The Main Orchestrator stays attached and
looping until every issue is terminal (completed / failed-review / failed-merge / blocked).
Per-issue dispatcher PIDs are persisted by the platform pool runner.
The pool runner must also perform each terminal per-issue GitHub update immediately after finalizing that issue's compact report: post the terminal comment populated from the report, close the issue when `outcome=completed`, leave `blocked` and `failed-review` issues open after commenting, and emit `STATUS|type=github-update|issue=<n>|outcome=<outcome>|action=<commented|skipped|failed>|closed=<true|false>`.
══ GOTO STEP A ═════════════════════════════════════════════════════════════════
Platform Dispatchers — Shared Role Launcher
run-with-it-dispatch.sh and run-with-it-dispatch.ps1 are the shared run-with-it orchestration primitives. The Main Orchestrator uses them with role=sub-coord; Sub-Coordinators use them with role=complexity, plan, impl, review, or modify. They wrap run-agent.sh / run-agent.ps1, forward the role-specific RUN_WITH_IT_* environment, write dispatch status lines, capture stdout/stderr into the role log, monitor done/result artifacts through worker-watch.sh / worker-watch.ps1, and write a dispatcher-owned watchdog state file. Model-emitted heartbeats remain advisory; the runner-owned wrapper-heartbeat and dispatcher state are the liveness authority, independent of model stdout.
When a Sub-Coordinator launches worker dispatchers from a short-lived shell/tool call, use --detach on Bash or -Detach on native PowerShell, then read the dispatcher PID from the dispatcher-owned state file. Do not rely on a raw shell background job and WORKER_PID=$! for worker dispatches.
Bash --detach creates a new process session/process group before returning. This is required because plain nohup ... & can remain attached to the tool-call process group and be killed before the worker runner PID is recorded.
If a detached worker dispatcher exits or emits STATUS|type=dispatch-bootstrap-failed before the state file records runner_pid, treat it as launch bootstrap loss rather than a worker/model result. Retry the same worker once in foreground monitor mode with the same log, done, result, state, repo-root, issue-dir, status, and events paths so the dispatcher captures either dispatch-pid or a concrete artifact failure.
Worker result files must never be $SUB_COORD_REPORT_FILE or .run-with-it/issues/<n>/report.json — see coordinator-rules.md (Worker-Agent Dispatch Rules) for the full path contract.
run-with-it-dispatch.sh \
--role <sub-coord|complexity|impl|review|modify|merge-recovery> \
--issue <n> \
--cycle <n> \
--agent <agent> \
--model <model> \
--context-file <file> \
--prompt-file <file> \
--log-file <file> \
--done-file <file> \
--result-file <file> \
--state-file <file> \
--repo-root <worktree-or-repo-path> \
--status-file <file> \
--events-log <file> \
--quiet-seconds <seconds> \
--stall-seconds <seconds> \
--detach
PowerShell uses the same field names with PowerShell-style parameters, for example -Role impl -Issue 123 -LogFile <file> -DoneFile <file> -ResultFile <file> -StateFile <file> -Detach.
Use --dry-run / -DryRun to print the wrapped runner invocation, and --validate-only / -ValidateOnly to verify inputs and emit STATUS|type=dispatch-ready without spawning.
Worker watchdog files use the issue-scoped layout cycle-<cycle>.state.json. state="quiet" and state="stalled" describe model-output health while runner-owned wrapper heartbeats track process liveness. state="artifact-recovery-required" means Git progress was preserved without machine-readable passing verification and must enter artifact recovery. Completion still requires the done sentinel, valid role-specific result artifacts, and passing implementation/modification verification.
RUN_WITH_IT_AUTO_FAIL_STALLED_ROLES (Bash default: complexity,impl,modify,plan) is a compatibility fallback for older runners without wrapper heartbeats. Current runners are not terminated for quiet stdout alone; RUN_WITH_IT_WORKER_HARD_LIMIT_SECONDS bounds elapsed execution, preserving Git progress for recovery before termination.
Final PR Creation
After all issues are terminal and before gh pr create, render the PR body from the persisted run state:
"$ASSET_ROOT/run-with-it-pr-body.py" render --state-file .run-with-it/main-state.json > .run-with-it/final-pr-body.md
gh pr create --body-file .run-with-it/final-pr-body.md
The rendered body must list completed/closed issues as plain issue links such as #123. Do not use auto-closing keywords in the final PR body because issues are already closed by the per-issue GitHub update flow. Ban case-insensitive auto-closing keyword variants adjacent to issue refs: close, closes, closed, fix, fixes, fixed, resolve, resolves, resolved.
run-agent.sh — Full Syntax Reference
run-agent.sh --agent <agent> [--model <model>] --context-file <file> [--prompt-file <file>]
[--permission-mode <mode>] [--extra-arg <arg>] [--unattended] [--dry-run]
run-agent.sh --list-agents [--detected-only]
run-agent.sh --list-models <agent>
| Flag | Env var equivalent | Required | Description |
|---|---|---|---|
--agent <agent> | AGENT | Yes | Enabled agent slug (e.g. codex, claude, agy; github-copilot/copilot is registry-disabled while the Copilot plan is exhausted) |
--model <model> | MODEL | Yes (always pass explicitly) | Model id to use |
--context-file <file> | CONTEXT_PAYLOAD_FILE | Yes | Path to the assembled context payload file |
--prompt-file <file> | PROMPT_FILE | No (defaults to <script-dir>/prompt.md) | Path to the prompt file |
--repo-root <path> | REPO_ROOT | No | Working directory passed to the agent; Sub-Coordinators use issue worktrees |
--permission-mode <mode> | AGENT_PERMISSION_MODE | No | Override agent permission mode |
--extra-arg <arg> | AGENT_EXTRA_ARGS | No | Repeatable; appended to agent invocation |
--unattended | UNATTENDED=1 | Yes — always pass in run-with-it dispatches | Required whenever a permission mode is set |
--dry-run | — | No | Print the resolved command without executing |
--list-agents | — | — | List all agents and detection status; add --detected-only to filter |
--list-models <agent> | — | — | List known models for an agent |
Additional env vars (no flag equivalents):
| Env var | Default | Description |
|---|---|---|
AGENT_REGISTRY_FILE | <script-dir>/agent-registry.json | Path to agent registry |
GUI_MODE | auto | auto detects GUI env vars; 1 forces GUI-safe noninteractive mode; 0 forces CLI/CI mode |
REPO_ROOT | $(pwd) | Working directory passed to agent |
PRINT_PROMPT | 0 | Set to 1 to print assembled prompt without running |
GUI_MODE behavior:
auto— detectsVSCODE_PID,TERM_PROGRAM=vscode,ELECTRON_RUN_AS_NODE,ANTIGRAVITY_APP,CURSOR_TRACE_ID,CLAUDE_CODE_ENTRYPOINT; setsGUI_MODE=1if any match.1— forcesUNATTENDED=1and downgrades dangerous full-bypass permission flags to safer per-agent equivalents.0— preserves CLI/CI behavior with no permission downgrades.
Cleanup
Cleanup runs only after a successful completion, failed run, interrupted run, or explicit discard command. Cleanup must not fire on resume.
Successful Run Completion
On successful run completion:
- Delete all
$SUB_COORD_CONTEXT_FILEtemp files (should already be deleted after each issue, but clean up any stragglers). - Delete
.run-with-it/main-state.json,.run-with-it/main-orchestrator-rules.md,.run-with-it/coordinator-rules.md. - Before deleting tracked files, worktrees, or any file outside
.run-with-it/, print the planned cleanup targets and ask the user to confirm. After confirmation, delete generated files under.run-with-it/issues/,.run-with-it/main/,.run-with-it/status/,.run-with-it/worktrees/, and.run-with-it/locks/. - Remove issue worktrees with
git worktree removewhen possible. Preserve the shared run feature branch after final PR creation. - Remove
.run-with-it/directory if empty. - For each of
technical_requirements.md,prd.md, andissues.mdpresent in the workspace root: rungit status --short <file>. Delete the file only if it is untracked (??) or clean (not listed). If the file has user modifications (any other status), skip deletion and emitSTATUS|type=cleanup|action=skipped-dirty-file|file=<file>— never delete user-modified workspace files. - Ensure
.gitignorecontains entries for.run-with-it/,technical_requirements.md,prd.md, andissues.mdusing an idempotent append. - If
.git/exists, stage only the deleted files and.gitignore; commit with messagechore: remove skill-generated artifacts post-run. - Emit
STATUS|type=cleanup|action=completed|files_removed=<n>.
Failed or Interrupted Run
On failed or interrupted run:
- Keep all
.run-with-it/files, including preserved worktrees and locks for inspection. - Print the paths of preserved files (state, reports, logs, reviews).
- Offer
discardcommand to force-delete and restart.
Discard
On discard, terminate all detached run processes BEFORE deleting anything. The
supervisor, dispatchers, and runners are detached: left running, they will keep
writing into deleted or newly recreated paths and can still perform GitHub
updates. Killing only a dispatcher PID is NOT enough — runners are spawned
separately (nohup / Start-Process) and outlive their dispatcher.
-
Run the platform stop helper — it terminates and verifies complete Unix process groups / Windows process trees for every PID recorded in run state (
pool_pid, everydispatcher_pidandrunner_pid, including nested worker and recovery dispatchers), after an identity check on each PID's command line so reused PIDs belonging to unrelated processes are never signaled:Bash:
"$ASSET_ROOT/run-with-it-stop.sh" --run-root "$(pwd -P)"PowerShell:& powershell -NoProfile -File (Join-Path $ASSET_ROOT "run-with-it-stop.ps1") -RunRoot (Get-Location).PathThe helper prints one
STOP|type=target|...line per PID and a finalSTOP|result=<clean|survivors>|terminated=<n>|already_dead=<n>|skipped_not_ours=<n>line. -
Refuse discard if termination cannot be established. The stop helper exits 3 and reports
STOP|result=survivors|...|survivors=<pids>when any targeted process is still alive after escalation. Report the surviving PIDs to the user and stop; do not delete state out from under live processes. -
Print the planned discard targets and ask the user to confirm before deleting. After confirmation, delete preserved generated files including
.run-with-it/main-state.json,.run-with-it/main/pool.state.json, reports, logs, reviews, worktrees, locks,technical_requirements.md,prd.md, andissues.md. -
Update
.gitignoreand commit with messagechore: remove skill-generated artifacts (discarded run). -
Emit
STATUS|type=cleanup|action=discarded|files_removed=<n>. -
Proceed as a fresh run.
Appendix A: Main State Schema
The Main Orchestrator persists .run-with-it/main-state.json (schema_version 4). This is the Main Orchestrator's entire persistent memory.
{
"schema_version": 4,
"run_id": "<funny-action-animal slug generated at run start>",
"started_at": "<iso8601>",
"run_branch": {
"base_branch": "main",
"base_sha": "abc123",
"feature_branch": "Maestro/cunning-fox",
"feature_branch_start_sha": "abc123",
"remote": "origin",
"pushed": true,
"pr_url": null
},
"execution_plan": {
"execution_mode": "sequential | rolling-pool",
"concurrency_policy": "strict",
"parallel_jobs": 4,
"topo_order": [36, 37],
"dependency_tiers": [[36], [37]],
"pool_config": {
"max_concurrent": 4,
"fill_strategy": "rolling"
}
},
"issue_registry": {
"36": {
"status": "completed | in_progress | pending | merge_recovery | failed-review | failed-merge | blocked",
"title": "issue title",
"deps": [],
"dependency_proof": "Blocked by: None",
"parallel_safe": true,
"ownership_scope": ["src/orders"],
"issue_dir": ".run-with-it/issues/36",
"report_file": ".run-with-it/issues/36/report.json",
"merge_recovery_report_file": ".run-with-it/issues/36/merge-recovery-report.json",
"log_file": ".run-with-it/issues/36/sub-coordinator.log",
"issue_branch": "Maestro/cunning-fox-issue-36",
"worktree_path": ".run-with-it/worktrees/issue-36",
"issue_base_sha": "abc1234",
"issue_base_source": "remote-tracking | local-fallback",
"commit_sha": "abc1234"
}
},
"active_pool_issues": [37, 38],
"completed_summaries": [
{
"issue": 36,
"outcome": "completed",
"summary": "One paragraph compact report summary.",
"files_modified_count": 3,
"lines_added": 42,
"lines_deleted": 7,
"review_cycles": 1,
"commit_sha": "abc1234",
"verification": {
"passed": true,
"evidence": "15 tests passed, 0 failed"
},
"model_usage": [
{
"role": "impl",
"cycle": 1,
"agent": "codex",
"model": "gpt-5.3-codex",
"selection_reason": "under-target"
}
],
"report_file": ".run-with-it/issues/36/report.json"
}
],
"ledger_rows": [
"STATUS|type=ledger|task=36|... (verbatim line as emitted)"
]
}
Key invariants:
issue_registryhas one entry per issuerun_branchcaptures the shared feature branch used for the final PRtopo_orderanddependency_tiersare derived from issue dependency topological sortingcompleted_summariesaccumulates one compact record per finished issue, including compactsummary,verification,model_usage, andreport_filefields — this is what the main orchestrator reads back after compressionmerge_recoveryis non-terminal; dependencies are satisfied only bycompletedledger_rowsstores verbatim STATUS lines for the final ledger printoutactive_pool_issueslists which issues have active Sub-Coordinators; on resume follow the Resume Flow in Appendix C — validate the supervisor lease and preserve active state, because detached dispatchers may still be running- When
PARALLEL_JOBS=1,active_pool_issuesalways has at most one entry
.gitignore Auto-Append for .run-with-it/ (Required)
On the first write of any file under .run-with-it/:
- If
.git/exists in the current working directory, ensure.run-with-it/is in.gitignore:- Create
.gitignoreif it does not exist - Append
.run-with-it/on its own line only if not already present (idempotent) - Preserve existing
.gitignorecontents unchanged
- Create
- If
.git/is absent, skip.gitignorecreation silently.
Appendix B: Status and Ledger Contract
Status Messages
Emit parseable one-line status messages:
- plan:
STATUS|type=plan|total_issues=<n>|mode=<sequential|rolling-pool>|parallel_jobs=<PARALLEL_JOBS>|pending=<n>|blocked=<n> - pool fill:
STATUS|type=pool-fill|active=<count>|newly_queued=<count>|pending_remaining=<count>|parallel_jobs=<PARALLEL_JOBS> - pool slot filled:
STATUS|type=pool-slot-filled|issue=<n>|freed_by=<m>|pool_size=<count> - pool detached:
STATUS|type=pool-detached|pid=<pid>|pool_state_file=<path> - pool already running (duplicate launch refused, exit 2):
STATUS|type=pool-already-running|pid=<pid>|pool_state_file=<path> - pool reattached:
STATUS|type=pool-reattached|count=<n>|state_file=<path> - sub-coordinator reattach:
STATUS|type=sub-coord-reattach|issue=<n>|pid=<pid>|identity=<live|stale|dead>|report_file=<path>—stalemeans the recorded PID is alive but its command line no longer matches a dispatcher (recycled PID); it is never adopted and enters exit analysis - pool admission deferred:
STATUS|type=pool-admission-deferred|count=<n>|deferrals=<issue:reason,...> - pool unreachable:
STATUS|type=pool-unreachable|count=<n>|unreachable=<issue:root,root;...>— issues that can never become ready because a dependency ended terminal-but-not-completed.rootnames the terminal issue to blame, attributed transitively. Repeated with|final=1when the pool drains, so a run that ends early always says which failures stranded what. - sub-coordinator recovery wait:
STATUS|type=sub-coord-recovery-wait|issue=<n>|role=<role>|worker_state=<state>|state_file=<path>|reason=in-flight-worker-running|waited_seconds=<n>|worker_age_seconds=<n>|max_wait_seconds=<n>— throttled toWAIT_STATUS_INTERVAL_SECONDS;worker_age_secondsis how long since any of that worker's artifacts moved - pool empty:
STATUS|type=pool-empty|pending_remaining=<n> - merge recovery queued:
STATUS|type=merge-recovery|issue=<n>|report_file=<path>|state=<started|completed|failed-merge|blocked> - memory refresh:
STATUS|type=memory-refresh|state_file=.run-with-it/main-state.json|tasks_loaded=<n>|completed=<n>|pending=<n>|failed=<n> - main loop:
STATUS|type=main-loop|iteration=<n>|pending=<count>|completed=<count>|failed=<count> - sub-coordinator spawn:
STATUS|type=sub-coord-spawn|issue=<n>|agent=<name>|model=<model>|report_file=<path>|log_file=<path>|pool_size=<n>|parallel_jobs=<PARALLEL_JOBS> - sub-coordinator pid-tracked:
STATUS|type=sub-coord-pid|issue=<n>|pid=<pid>|done_file=<path>|report_file=<path> - live agent start:
STATUS|type=agent-start|issue=<n>|role=<sub-coord|complexity|impl|review|modify>|agent=<name>|model=<model> - live agent complete:
STATUS|type=agent-complete|issue=<n>|role=<sub-coord|complexity|impl|review|modify>|agent=<name>|model=<model>|status=<success|failed> - worker done:
STATUS|type=worker-done|issue=<n>|role=<complexity|plan|impl|review|modify>|phase=<phase>|source=<agent|runner-exit> - sub-coordinator complete:
STATUS|type=sub-coord-complete|issue=<n>|outcome=<completed|failed-review|merge_failed|blocked>|report_file=<path>|commit_sha=<sha-or-none> - merge start:
STATUS|type=merge-start|issue=<n>|branch=<issue_branch>|target=<feature_branch> - merge complete:
STATUS|type=merge-complete|issue=<n>|merge_sha=<sha>|pushed=<true|false> - merge failed:
STATUS|type=merge-failed|issue=<n>|reason=<conflict|verification|push|unknown> - stall:
STATUS|type=stall|issue=<n>|idle_for=<seconds>|action=alert-user - intake fallback:
STATUS|type=intake-fallback|reason=<no-gh-auth|no-remote|gh-permission-blocked|gh-failed-after-escalation> - runner sandbox retry:
STATUS|type=runner-sandbox-retry|agent=<agent>|model=<model>|reason=<error-summary> - runner sandbox retry result:
STATUS|type=runner-sandbox-retry-result|outcome=<success|failed> - cleanup completed:
STATUS|type=cleanup|action=completed|files_removed=<n> - discard shutdown (from the stop helper):
STOP|type=target|source=<pool|dispatcher|runner>|pid=<pid>|action=<term-group|term-pid|stop-tree|already-dead|skip-not-ours>followed bySTOP|result=<clean|survivors>|terminated=<n>|already_dead=<n>|skipped_not_ours=<n> - cleanup discarded:
STATUS|type=cleanup|action=discarded|files_removed=<n> - final ledger row:
STATUS|type=ledger|task=<task-id>|role=impl|cycle=0|agent=<agent-name>|model=<model-id>|added=<n>|deleted=<n>|total=<n>|reason=sub-coordinator|input_tokens=<n-or-unknown>|output_tokens=<n-or-unknown>|cache_hit_tokens=<n-or-unknown>|telemetry_source=sub-coordinator-report
Final Ledger
After the loop exits and before cleanup, print the aggregated final ledger by reading ledger_rows from main-state.json. This means the ledger survives compression and captures all issues including those completed before the context was compressed.
Also print a final summary of all completed_summaries entries showing:
- Total issues processed
- Completed / failed-review / failed-merge / blocked counts
- Total lines added/deleted across all issues
- Task-level model usage (
role,cycle,agent,model,selection_reason) from each issue'smodel_usage - Aggregate token usage (sum
token_usagefields from all report JSONs for issues that have completed)
Appendix C: Resume and State Contract
Resume Flow
On startup, if .run-with-it/main-state.json exists, prompt the user (per Preflight Check 6, existing-state detection). On resume:
- Re-read
.run-with-it/main-state.json. - Validate the supervisor lease first. The pool supervisor and dispatchers run
detached, so they may still be alive from the interrupted session. Read
.run-with-it/main/pool.state.jsonand checkpool_pid:- Supervisor alive (PID exists and its command line references the pool
runner, e.g.
ps -p <pid> -o command=containsrun-with-it-pool): do NOT reset anything and do NOT relaunch. Re-enter the Step D watch loop against the existing supervisor and continue untilWATCH|result=pool-empty. - Supervisor dead (missing state file, dead PID, or PID reused by an
unrelated process): relaunch the detached pool runner. It re-attaches to
active_pool_issues— live dispatchers keep running under the new supervisor; dead ones flow through structured exit analysis.
- Supervisor alive (PID exists and its command line references the pool
runner, e.g.
- Never bulk-reset
in_progressissues or clearactive_pool_issues. Resetting an issue whose detached dispatcher is still alive dispatches it a second time: duplicate work, merges, state writes, token cost, and GitHub comments. Requeue an individual issue topending(viarun-with-it-state.py requeue) only when structured evidence proves its dispatcher is dead — dead dispatcher PID in the issue's dispatcher state file — AND no issue-scopedsub-state.jsonsupports recovery. The pool runner's re-attach path already performs this analysis; prefer relaunching the pool over manual requeues. - Identify all issues with
status="pending"— these haven't started yet. - Identify all issues with
status="completed","failed-review","failed-merge", or"blocked"— skip these entirely. - Re-enter Main Loop at Step A.
- Emit:
STATUS|type=resume|tasks_restored=<n>|completed=<n>|supervisor=<alive|relaunched>|re_queued_in_progress=<m>|parallel_jobs=<PARALLEL_JOBS>
If .run-with-it/main-state.json is missing or unparseable when the user types resume, emit:
STATUS|type=resume-error|reason=<missing|parse-error>|action=user-required
Then stop and ask the user whether to proceed as a fresh run.
Compression Survival
After context compression (conversation history cleared), treat the situation as a resume: re-read .run-with-it/main-state.json per Step A, then follow the Resume Flow above — validate the supervisor lease and preserve active state. The pool supervisor and dispatchers run detached and are unaffected by compression; they are almost certainly still alive, so re-enter the watch loop rather than touching issue state. completed issues are never re-run. The state file is always authoritative — never derive issue state from conversation history.
Appendix D: Terminal Issue Comment Contract
Terminal Issue Comments
Post issue comments immediately for terminal outcomes: completed, blocked, failed-review, or failed-merge (set after merge recovery fails).
Each terminal comment must be posted only after reading the compact report for that issue, and must not wait for unrelated issues or the full pool to finish.
Populate all fields from the Sub-Coordinator's compact report JSON.
Use the same markdown template for every terminal outcome, with this fixed section order:
## Status## Summary## Verification## Token Usage## Notes## Blocking Reasons(only whenreport.blocking_reasonsis non-empty)
Terminal comment template:
## Status
<completed|blocked|failed-review|failed-merge>
## Summary
<task outcome summary — from report.summary>
## Verification
<task-specific verification results — from report.verification.evidence>
## Token Usage
- Input tokens: <n|unknown>
- Output tokens: <n|unknown>
- Cache hit tokens: <n|unknown>
## Notes
Review: <approve|revise (N cycles)>, final verdict: <approve|reject>, reviewer model: <model-id>
<follow-ups, blockers, or additional reviewer notes — omit line if none>
## Blocking Reasons
<omit this section entirely when verdict is not reject; when verdict=reject, list each entry from report.blocking_reasons as a separate bullet>
Comment requirements:
Token Usagemust report task-specific telemetry only (fromreport.token_usage).- If any token value is unavailable, render that value explicitly as
unknown. Verificationmust summarize the checks run and whether they passed, failed, or were blocked (fromreport.verification).Notesmust include exactly one review summary line whenDELEGATED_REVIEW=trueand review ran. Format:Review: <verdict-path>, final verdict: <approve|reject>, reviewer model: <model-id>. For a straight approval writeapprove (1 cycle); for a revise-then-approve writerevise (N cycles). Whenreport.review_skippedis true, writeReview: skipped (trivial-change)instead.Blocking Reasonssection must be included only whenreport.blocking_reasonsis non-empty. Render each entry as a separate markdown bullet. Omit the section entirely otherwise.
How can the creator link this skill?
Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.
<a href="https://skillzs.dev/skills/chanakya-net/maestro-ai/run-with-it">View run-with-it on skillZs</a>