agent-delegation
Skill4 starsChanged 2 months agoMITView on GitHub
Run any coding-agent CLI (codex, cursor, codebuddy, claude, omp, opencode, deepseek-harness) as a detached background worker on a git worktree — dispatch it, watch the sentinel it writes, relay a finished reviewer into its own fix, and prove what it claims. Use when handing a long task to an agent CLI, when a dispatched run needs watching or has gone quiet, when a review's findings should become the next run, or when a run reports a lock it never proved.
- Reads credentials
2 other projects use a version of this.
Adopted by
Most recently taken up by
- yeisonrestrepo/code-conductortheir own version, first seen Oct 6, 2026
- kangarooking/system-prompt-skillstheir own version, first seen May 4, 2026
Other versions2 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 2
- kangarooking/system-prompt-skills★ 178same name
- yeisonrestrepo/code-conductor★ 17same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
The file
We split this skill into the rules it gives an agent
6 rules. About 0 are common, 3 are distinctive, and 3 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈3
Distinctive · estimate
This author's own choices. Worth a look.
3
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 103
Every run writes four files named for it, so its state is answerable from disk rather than from the agent's own account:
- Distinctive: line 187
Never block on a run: Not a foreground wait, not a sleep loop.
- Distinctive: line 228
Check the staged set against what the change should touch: If the run rebased or reset onto a moving trunk, the index can quietly contain …
- Very specific: line 255
When a read-only reviewer finishes and its findings *are* the follow-up work, resume that same session rather than briefing a fresh one — …
- Very specific: line 307
Reachability: Ask for the assertion sites as file:line before asking about mutations.
- Very specific: line 328
Start from templates/brief.md (implementation) or templates/review.md (read-only review).
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Agent Delegation
A subagent shares your context budget and your turn; a detached CLI worker does neither. It gets its own window, runs for hours after your turn ends, and costs you only the brief you write and the result you read. That makes it the right shape for work measured in hours — and the wrong shape for anything you'd rather just do.
This skill covers the running of such a worker, across seven CLIs behind one entry
point. Scripts come in both .sh and .ps1; they behave identically, and both run on
Windows, macOS, and Linux.
The seven lanes
| agent | CLI | write lane | read-only lane | resume |
codex | codex exec | --dangerously-bypass-approvals-and-sandbox | omit it — its own sandbox is read-only | codex exec resume <sid> |
cursor | cursor-agent | --force | --plan --trust | none — dispatch fresh |
codebuddy | codebuddy | -y --permission-mode bypassPermissions | omit them | --resume <sid> |
claude | claude | --dangerously-skip-permissions | omit it | -r <sid> |
omp | omp -p | --approval-mode yolo | --approval-mode always-ask | -r <session file> |
opencode | opencode run | --auto | --auto plus a deny-only agent | --session <sid> |
deepseek-harness | dsh --profile headless | preset danger-full-access | preset read-only | none — one task per process |
No model id is hard-coded anywhere in this skill. Pass --model, or set
AGENT_MODEL_<AGENT> / AGENT_MODEL. Ids change; a stale default fails late and looks
like a task problem rather than a config one. Hyphens in an agent name become underscores
in its variables (AGENT_MODEL_DEEPSEEK_HARNESS), AGENT_CLI_<AGENT> retargets the
executable, and deepseek-harness takes <provider>/<model> because dsh routes by
provider.
Four differences fail silently if you get them wrong:
How the brief reaches the agent. codex takes it on stdin, so multi-line quoting
never has to survive a shell. The others take argv — and passing a large brief as an argv
element makes the CLI return immediately with a few-byte log and exit code 0, which a
monitor reports as DONE. So they are handed the brief's path and read the file
themselves. The dispatch scripts already do this.
An open stdin. Measured: opencode run with an inherited stdin sits there forever
— no output, no .exit, a zero-byte log, indistinguishable from a dead run. The same
command with stdin on /dev/null exits in under two seconds. (--auto happens to mask it
too, which is how it hides: the write lane looks fine and the read-only lane hangs.) Every
lane is launched with stdin closed for that reason; do not "simplify" it away.
What the read-only lane actually blocks. It is not the same guarantee twice:
| agent | read-only lane blocks | still possible |
codex | writes, at the OS sandbox | reading, running commands |
cursor | everything — planning mode, no execution | nothing |
codebuddy, claude | anything needing an approval nobody can give | pre-approved reads |
omp | write, bash, and eval alike — each refuses with "requires approval but no interactive UI available" | reads, greps, globs |
opencode | the mutating tools, removed and denied | bash — a shell redirect still writes |
deepseek-harness | writes, at the sandbox; approvals fail closed with no answerer | reading, running commands |
Two of those are worth stating plainly, because the obvious guess is wrong in both:
omp -p writes files with no permission flag at all, so omitting one does not make a
reviewer read-only; and opencode's own plan agent sets edits to ask, which --auto
then approves — --agent plan --auto is a writing agent. The dispatch script ships its own
deny-only agent definition through OPENCODE_CONFIG_CONTENT, which outranks any
opencode.json sitting in the tree.
Because opencode's read-only lane stops at the tool boundary rather than the OS, treat its
.before diff as the real check — see Harvest — not as a formality.
Permissions and models that live in a settings file, not in a flag.
dsh --profile headless has no --model and no permission flag: both come from its
settings document, and the saved selection there beats a --patch overlay — measured,
by patching agent-default-model and watching the run go to the provider the settings
named anyway. So each dsh run gets its own settings file: the user's, minus the two blocks
the run owns, plus its own, with a one-row patch pointing the settings plugin at it. The
rest is copied because that is where custom provider routes are declared; regenerating it
from scratch would drop them.
dsh also splits its streams — stdout is exactly the final answer, stderr is reasoning
plus dsh: <CODE>: <message> — so its .out is the deliverable with no tail heuristic.
A run that produced no answer still prints one blank line, so the dispatch normalises a
whitespace-only .out back to empty; otherwise result=MISSING would silently become
result=1.
Preflight
Never dispatch into a path you have not made git resolve. A worktree removal that
fails partway leaves the files but drops the .git pointer, and from then on git walks
up and resolves that directory to the main repository. An existence check passes.
A dispatch into it edits the trunk.
The dispatch scripts make git resolve the path and refuse to launch when
rev-parse --show-toplevel disagrees with the directory they were handed.
That check cannot catch the main repo being passed in — a repo resolves to itself, so
it prints preflight ok and dispatches straight into the trunk. It is guarded separately,
by comparing against the parent of --git-common-dir. Keep both; they catch different
things.
The sentinel quartet
Every run writes four files named for it, so its state is answerable from disk rather than from the agent's own account:
| file | written | what it answers |
.before | at dispatch | the tree's git status --porcelain --ignored |
.log | streaming | what happened, in full |
.out | at the end | the deliverable — the run's final message |
.exit | last | it finished, and with what code |
.exit is written after everything else precisely so its existence is the completion
signal. scripts/watch.sh reads the quartet across all run directories.
An empty .out is a failed run, whatever the exit code says. The transcript is not the
deliverable; a run that ended without producing one produced nothing.
Watch for the run that died on credentials. An upstream 401 ends the run with a
complete sentinel — .exit is written, .out is empty — so the monitor reports DONE,
not DEAD, and only result=MISSING distinguishes it. Split the two cases at a glance:
.out empty + log has 401/INVALID_API_KEY => credentials/upstream. Re-dispatch.
.out empty + log has no 401 => it really produced nothing. Read the brief.The watcher names the cause when it can read one, in the CLIs' own wording — cause=AUTH
for an invalid key, cause=LIMIT for a 429 or an exhausted quota:
DONE deepseek-harness/probe exit=1 result=MISSING cause=AUTH
DONE opencode/probe exit=1 result=167 cause=AUTHThe second line is the one to be careful with. On every lane whose .out is the tail
of the transcript, a run that failed upstream still leaves a non-empty .out — the error
text, sitting exactly where a deliverable goes. result=167 is not a result. That is why
the watcher scans the log on any nonzero exit, not only on an empty .out, and why a
nonzero exit is never worth skimming past.
Do not conclude "transient" from the other runs still going. Sessions already established do not re-authenticate — the token is in the session, and only new connections refresh. So "the others are fine" is not evidence about credentials at all. Judge from newly dispatched runs; two new ones failing means the config changed.
Not every CLI streams. Some print only at the end, so .log stays at zero bytes for
the whole run and log growth cannot tell you whether it is alive. Fall back to process CPU
time and the tree's own state (HEAD, dirty count, branch pointer).
Measure logs with a stat call, not a directory listing. Some shells' listing commands
report a cached directory entry — 0 bytes — for a file being actively written, which
reads exactly like a dead run.
Requirements: the chosen CLI on PATH (or AGENT_CLI_<AGENT> pointing at it), a git
repository, and bash 3.2+ or PowerShell 7. AGENT_RUNS relocates the sentinel directory
(default <repo>/.agent-runs/<agent>/); AGENT_EFFORT / AGENT_EFFORT_<AGENT> set the
reasoning level where the CLI has one — codex's model_reasoning_effort, omp's
--thinking, opencode's --variant. dsh has no such flag and ignores it.
Platform. Both script sets run everywhere: the bash scripts hold to bash 3.2, because
that is still the system bash on macOS — the earlier declare -A in the watcher loop was
a bash 4 feature that died on its first line there. The PowerShell scripts do no
\-shaped path arithmetic (git speaks forward slashes on every platform), take the temp
directory from the runtime rather than %TEMP%, and fall back to powershell where
pwsh is absent. The bash watcher loop calls bash scripts/watch.sh rather than executing
it directly, so a checkout that lost the execute bit still works — that one was live: the
scripts were committed mode 644, which made the direct call "permission denied", and the
loop reported nothing at all while looking perfectly healthy. The bit is set now; the
indirection stays, because the next checkout is not obliged to keep it.
Wiring it into an agent host
Arm one persistent watcher for all runs, before the first dispatch — for example, in Claude Code:
Monitor({command: "bash <skill>/scripts/watch-loop.sh", persistent: true,
timeout_ms: 3600000, description: "agent runs finishing or dying"})On Windows, or any host without bash: pwsh -NoProfile -File <skill>/scripts/watch-loop.ps1.
One watcher covers every run, including ones dispatched later. Per-run watchers multiply notifications for nothing and risk a flood cut-off.
Never block on a run. Not a foreground wait, not a sleep loop. Runs last hours; the watcher is what tells you, and your turn ends long before they do.
The notification is a pointer, not the content. DONE codex/name exit=0 result=12268
says a deliverable exists — it does not say what it concluded. Read .out before deciding.
Refill the slot the moment one frees. The costly failure is not running too many at once — it is several finishing together, you harvesting them all, and nothing new going out while you write up results. Dispatch the next brief before writing the summary.
Parallelism ceilings are per-account and differ per lane. Find each one: raise the count until runs start failing on rate limits, then stay one below. Heavy-IO work (rebases, repeated test collection, full static runs) belongs on the slowest-contended disk you have.
The loop
Each completion runs the same cycle:
- Read
.out. Missing or empty → treat as failed, whatever the exit code says. - Harvest (below) — diff the tree against
.before, verify the claims. - Route by what you find:
- clean → dispatch a fresh run to review it (
templates/review.md) - review found real defects → relay that reviewer into fixing them
- review passed → merge, and dispatch the next piece of work
- clean → dispatch a fresh run to review it (
- Refill the slot in the same turn.
The invariant that holds the loop together: the run that changed the code is never the run that approves it. Everything else here is machinery serving that one rule.
Harvest
Diff .before against the tree's git status --porcelain --ignored now. Plain
--porcelain hides ignored paths — a run that wrote a large dependency tree shows a clean
status, and the snapshot proves nothing. Read the two lists against a stated allowance:
tool caches are expected; installed dependencies, writes outside the tree, and any
tracked-file change the brief did not authorise are violations.
State that allowance in the brief, as two explicit lists. "Modify nothing" and "run the test suite" contradict each other, and a run given both will either skip the tests or declare its own work invalid over a cache directory.
Check the staged set against what the change should touch. If the run rebased or reset
onto a moving trunk, the index can quietly contain the reverse of someone else's commit —
and nothing goes red. Measured twice: a run's staged set silently reverted a commit that
had landed an hour earlier, restoring a deleted assertion and rolling back a hash table.
Reading git diff --cached --name-status line by line is the check, and it is the only
thing that caught it.
A conflict inside a test file is the highest-risk resolution there is. When both sides appended tests, picking a side deletes a whole block of them and produces no red light. Require a union, and verify by comparing the set of test function names on both sides.
A green static gate does not mean nothing is red. Measured: a full static tier reported 45/45 with zero failures, and on the very same tree a consumer test failed immediately — the trunk had introduced a map that exhaustively enumerates an enum, and the branch's new enum member was not registered. No step in a "rebase → edit → re-measure → verify staged set → commit" checklist touches that. What finds it is asking "who reads the shape this module writes out?" and running those tests — not grepping for imports of the module, which measured about half the surface.
Replaying a commit is not the same as making one. git rebase does not fire
pre-commit hooks, so "the gate was green after the rebase" is an empty sentence. Read the
commit date, not the author date — rebase preserves the author date, so stale-looking
timestamps mean nothing. Adjacent commits landing seconds apart, when the gate takes
minutes, is the signal that no gate ran. The only reliable check is running it yourself.
Relay
When a read-only reviewer finishes and its findings are the follow-up work, resume that
same session rather than briefing a fresh one — it already holds the whole branch in
context. scripts/relay.sh (or .ps1) finds the previous session and continues it.
Where that session lives differs, and only one of the three shapes is a log scrape:
codex,codebuddy,claude— the id is in the previous.log.omp— the dispatch gave the run its own--session-dir, so the session is a path and-r <path>takes it directly. Nothing is scraped, so nothing can be misread.opencode— its own session index answers, listed from the worktree (opencode scopes that index by the invoking directory's project, so asking from anywhere else can miss the run entirely) and filtered to sessions created no earlier than the previous run's dispatch.
cursor and deepseek-harness have no resume lane and say so rather than degrading —
dsh's headless profile is one task per process by construction. Dispatch fresh and restate
the context.
The one invariant: whoever changed the code is never the one who signs off on it. Relaying a reviewer into a fix is sound — its review was written and harvested before it gained write access, so the fix cannot have coloured a conclusion that already exists on disk. Relaying again to bless that fix is not.
A relay that cannot find the session id must fail loudly. Starting a fresh session instead looks identical from the outside while carrying none of the context that justified relaying.
Prove it broke
Green is the default state. A test suite that passes proves nothing about a lock that was just written — an assertion that checks nothing passes exactly as loudly as one that guards the invariant.
So require, in the brief and again when reading the result: break the thing the lock guards, and show it going red. Paste the failure text, not a claim that it failed.
Ask the question at the level of the invariant, not the edit count. "How many places would I have to change to silence this lock?" is a proxy, and it was measured wrong in both directions: every string assertion answers "two", and every equality lock is built from two copies by construction. The durable form is:
What invariant does this lock claim to guard? Break that invariant — does anything go red?
Two operational faces of the same question, and a lock should survive both:
- change only production — can that silence it? (if yes, it never covered the case)
- degrade the assertion to trivially true — does anything else still go red? (if yes, something other than that assertion is load-bearing)
Two sharper forms, for when a run reports N locks:
- Independence. Breaking guard i must turn guard i red and leave the other N−1
green.
1 failed, N-1 passedis the shape that proves the guards can tell the cases apart; N reds from one break means one guard wearing N names. - Reachability. Ask for the assertion sites as
file:linebefore asking about mutations. A run that mutated N times and went red N times will otherwise report "N locks" when it has two. Red count is not lock count; site count is.
"It cannot be mutated" is a claim to distrust. Measured: a run reported a negative assertion as impossible to mutate. The real cause was a badly chosen mutation point — the naive edit crashed in unrelated setup before the assertion ran, and a leaked subprocess kept the test framework from printing the traceback. Two masking layers stacked. A different mutation point flipped it cleanly. Conclusions that cancel work need the strongest evidence, not the weakest.
Require proof the mutation landed. A replacement that missed its anchor produces a
green run indistinguishable from a lock that guards nothing — so demand git diff output
after each mutation, before the test run.
And require a restore point. git checkout -- <file> restores from the index, so
on a tree with uncommitted work it wipes the run's own fix along with the mutation. Stage
first.
Writing the brief
Start from templates/brief.md (implementation) or templates/review.md (read-only
review). Both encode the demands above; fill in the task-specific parts.
Four things belong in every brief and are easy to leave out:
Falsify first. Open with a probe that reproduces the defect on the current trunk, and an instruction to stop and report if it is already fixed. Work dispatched against a defect that no longer exists comes back as a plausible change to something else.
Name the tool by its exact invocation, not by its name. Pointing at a checker by name invites the wrong invocation, and the wrong invocation can fabricate failures rather than miss them: one type checker invoked directly reported hundreds of errors on a clean tree — all in unrelated files — while the project's own wrapper reported zero. Three separate runs stalled on that phantom before anyone ran the real command. Paste the exact line the gate config uses.
Check the brief against itself before sending. Measured four times in one day: a title that presupposed the answer to a question the body asked the run to decide; an environment block pinned to a different tree than the one the experiment names; a requirement and a prohibition that cannot both be satisfied. Three mechanical passes catch all of them — title vs. body, environment block vs. task, every requirement against every prohibition. And keep the title free of conclusions: name the subject, not the verdict.
Invite the rebuttal — then verify it. End with "tell me where this brief is wrong — argue it and show evidence." Briefs carry the author's causal guesses, and those fail far more often than the numbers in them do. But that section is a claim, not a finding. Split it on arrival: anything checkable by one command, check yourself; the rest is an unverified assertion and should be labelled one. Measured repeatedly: a run's correction ("that field does not exist in the artifacts", "those values appear nowhere in history") was itself wrong, was believed, and was written into the record. In each case the recommendation was right, which is exactly why nobody re-examined the reason.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

