Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ jobs:
shellcheck -S warning $files
- name: Node syntax
run: node --check skills/delegate-kit/scripts/agent-run
- name: Writer caps and detach refusal
run: bash skills/delegate-kit/tests/caps.sh
- name: SKILL.md stays a policy, not a manual
run: |
size=$(wc -c < skills/delegate-kit/SKILL.md)
Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ One skill for Claude Code, T3 Code and Codex CLI. Your logins, your subscription

Capable models already delegate. What they do inconsistently is *when* and *how*: a one-line fix spawns a 50k-token worker, a ten-module feature starts with no plan, three subagents share one working tree, and the author approves its own diff. delegate-kit makes one decision the same every time:

> **Do it here, send one scout, plan first, one worker, two or three in parallel, or a sequence — and who reviews the result.**
> **Do it here, send one scout, plan first, one worker, a few in parallel, or a sequence — and who reviews the result.**

| Without | With |
|---|---|
Expand Down Expand Up @@ -78,10 +78,10 @@ Two kinds of worker, never confused:
| **SCOUT** | the hard part is *finding*: a large repo, several plausible causes, docs to quote | one read-only worker, then decide again |
| **PLAN** | prose requirements, ambiguity, > 1 module or > ~10 files; any question that ends in a verdict | planner, read-only, strongest model |
| **SINGLE** | one vertical slice too big for DIRECT | one implementer in its own worktree |
| **PARALLEL** | 2–3 slices with disjoint write scopes and stable interfaces | one implementer per slice, each in a worktree |
| **PARALLEL** | 2+ slices with disjoint write scopes and stable interfaces | one implementer per slice, each in a worktree |
| **SEQUENTIAL** | one result changes the next task's assumptions (schema → API → UI) | one worker at a time, resumed |

Limits: 2 writers, 4 workers, delegation depth 1. Repository size changes the cost of *finding* context, not the number of writers.
Limits: writer cap 3, ceiling 8, workers = writers + 3, delegation depth 1. Raising the cap is a per-task decision: the coordinator names the partition (one ticket per writer, disjoint write scopes), you say yes, and `--max-writers N` carries it. Repository size changes the cost of *finding* context, not the number of writers.

## Review

Expand Down Expand Up @@ -183,7 +183,7 @@ agent-run resume <implementer-id> --prompt "Fix findings 1 and 3: ..."
agent-run list | status <id> | wait <id> | kill <id> | log <id> | notify [<id>]
```

Two writers in parallel: `--detach` on each, then `agent-run wait <id>` or `--on-finish CMD` so each reports for itself. A native writer: `agent-wt lock <task>` before dispatch, `agent-wt release <task>` after. `--help` on either script is the flag reference.
Several writers in parallel: `--detach` on each, then `agent-run wait <id>` or `--on-finish CMD` so each reports for itself. A native writer: `agent-wt lock <task>` before dispatch, `agent-wt release <task>` after. Both commands refuse a writer past the cap (`--max-writers N` or `DELEGATE_KIT_MAX_WRITERS` raise it, up to the ceiling of 8); a refused `--detach` run is reported to the parent. `--help` on either script is the flag reference.

</details>

Expand Down Expand Up @@ -212,7 +212,7 @@ skills/delegate-kit/
## What it will not do

- **Steer an external worker mid-run** — headless sessions run to completion; you read the result and resume. That is why native is preferred inside the family, and why an external worker is never called a subagent.
- **Run a swarm** — two writers, four workers. Larger fleets need an unusually clear partition and your explicit ask.
- **Run a swarm** — writer cap 3, ceiling 8, and the ceiling holds against every flag. Between the two it takes a stated partition and your yes, passed as `--max-writers N`.
- **Make delegation cheap** — a worker is a full session; the shapes exist so you pay for it only for independence, parallelism or a clean context.
- **Sandbox by itself** — the gate is a list of dangerous command shapes; the real isolation is the CLIs' own sandboxes plus the worktree.

Expand Down
48 changes: 24 additions & 24 deletions skills/delegate-kit/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ compatibility: Policy runs anywhere. Native workers need a host with subagents (

# delegate-kit

The current session is the **coordinator**: it owns the user's intent, the plan, every brief, integration, verification and the final answer. Workers are fresh sessions that start from a brief and read the repository themselves. Two kinds exist, and the policy names which one it means:
The current session is the **coordinator**: it owns intent, plan, every brief, integration, verification and the final answer. Workers are fresh sessions that start from a brief and read the repository themselves. Two kinds:

- **native** — a subagent of the host, same model family as the coordinator: steerable, visible, cheap.
- **external** — a headless CLI session of the other family (`claude -p` / `codex exec`) through `scripts/agent-run`: launched once, collected once, never steered. `references/external.md`.
Expand All @@ -18,44 +18,44 @@ Triage before acting. Pick the first shape that fits; state it in one line.

| Shape | When | Who |
|---|---|---|
| **DIRECT** | ≤ ~3 files with clear requirements; an explanation or diagnosis; a micro-fix after review; anything destructive or production-adjacent (`sudo`, deletes, services, secrets, prod DB, SSH) | coordinator, in the foreground |
| **SCOUT** | the hard part is *finding*: code spread across a large repo, several plausible causes, current docs to quote | one read-only worker (researcher for docs, otherwise the host's explorer) then triage again |
| **PLAN** | prose requirements with business rules, ambiguity that reading code cannot settle, > 1 module or > ~10 files; any reading that ends in a *verdict* ("which do we adopt", "is this upgrade safe") | planner, read-only, strongest model |
| **DIRECT** | ≤ ~3 files with clear requirements; an explanation or diagnosis; a micro-fix after review; anything destructive or production-adjacent (`sudo`, deletes, secrets, prod DB, SSH) | coordinator, in the foreground |
| **SCOUT** | the hard part is *finding*: code spread across a large repo, several plausible causes, current docs to quote | one read-only worker (researcher for docs, else the host's explorer), then triage again |
| **PLAN** | prose requirements with business rules, ambiguity code cannot settle, > 1 module or > ~10 files; any reading that ends in a *verdict* ("which do we adopt", "is this upgrade safe") | planner, read-only, strongest model |
| **SINGLE** | one well-specified vertical slice too large for DIRECT | one implementer in its own worktree |
| **PARALLEL** | 2–3 slices with disjoint write scopes, stable interfaces between them, each verifiable alone | one implementer per slice, each in its own worktree |
| **SEQUENTIAL** | a result changes the assumptions of the next task: schema → API → UI, diagnosis → fix | one worker at a time; the same worker resumed keeps its context |
| **PARALLEL** | 2+ slices with disjoint write scopes, stable interfaces, each verifiable alone; beyond the cap only as the limits below allow | one implementer per slice, each in its own worktree |
| **SEQUENTIAL** | a result changes the assumptions of the next task: schema → API → UI, diagnosis → fix | one worker at a time; resumed, it keeps its context |

Worker count equals the number of independent outcomes. Coupled edits stay in one pair of hands: split, they return as merge conflicts and two designs. Limits: 2 writers, 4 workers at once, delegation depth 1.
Worker count equals the number of independent outcomes. Coupled edits stay in one pair of hands: split, they return as merge conflicts and two designs. Limits: writer cap 3, ceiling 8; workers = writers + 3; delegation depth 1. Raising the cap is proposed like a review panel — partition stated, user's yes — and passed as `--max-writers N` (`references/external.md`).

**Routing trap:** "research" that ends in a recommendation is PLAN, not SCOUT. A quote is research; a verdict is planning, and a wrong verdict propagates downstream.
**Routing trap:** "research" that ends in a recommendation is PLAN, not SCOUT. A quote is research; a verdict is planning.

## 2. Spec, tickets and preset

- A grill/interview output or requirements longer than a paragraph → `.scratch/<task>/spec.md`; workers are pointed at it. An interview is not finished until the coordinator restates it in 5–8 lines — outcome, who it is for, what success looks like, the binding constraint, **out of scope** — and the user says yes explicitly; "sounds good" is not yes.
- Multi-slice work gets **tickets**: `/to-tickets` (mattpocock/skills) writes one file per tracer-bullet slice to `.scratch/<task>/issues/NN-slug.md` with `Blocked by`, `Status` and acceptance checkboxes. One ticket = one brief. The **frontier** — tickets whose blockers are all done — is the next work; a fresh session reads the directory and continues without being told where things stand.
- **Never overwrite a plan with unchecked items.** Replanning the same work edits the files in place; different work arriving while a plan is open is a question for the user, not a silent replacement.
- The user's words set the **preset**: any phrasing naming who carries the bulk of the work ("main model Claude", "let Codex implement") is `main-claude` / `main-codex`; naming a model for one role ("plan with Fable") is a per-call override. Presets move planner, implementer, researcher; the reviewer follows the author. `references/external.md`.
- A grill/interview output or requirements longer than a paragraph → `.scratch/<task>/spec.md`; workers are pointed at it. An interview ends only when the coordinator restates it in 5–8 lines — outcome, who it is for, what success looks like, the binding constraint, **out of scope** — and the user says yes explicitly; "sounds good" is not yes.
- Multi-slice work gets **tickets**: `/to-tickets` (mattpocock/skills) writes one file per slice to `.scratch/<task>/issues/NN-slug.md` with `Blocked by`, `Status` and acceptance checkboxes. One ticket = one brief. The **frontier** — tickets whose blockers are all done — is the next work; a fresh session continues from the directory alone.
- **Never overwrite a plan with unchecked items.** Replanning edits the files in place; different work while a plan is open is a question for the user, not a silent replacement.
- The user's words set the **preset**: naming who carries the bulk ("main model Claude", "let Codex implement") is `main-claude` / `main-codex`; naming a model for one role ("plan with Fable") is a per-call override. Presets move planner, implementer, researcher; the reviewer follows the author. `references/external.md`.

## 3. Route

Once per role: `agent-run route --role <role> [--preset P]`. Keep its answer — family, model, effort, native or external, exact invocation — for the whole task. `native` → dispatch through the host (`references/hosts.md`); `external` → `references/external.md`.
Once per role: `agent-run route --role <role> [--preset P]`. Keep its answer for the whole task. `native` → dispatch through the host (`references/hosts.md`); `external` → `references/external.md`.

## 4. Brief

Write every brief from `references/brief-template.md`: goal, spec, acceptance criteria as commands, where to look, constraints, worktree path, what to return. Done when a stranger with the repository and nothing else could start. An external worker cannot ask mid-run, so its brief also says: on ambiguity return `status: blocked` with precise `questions`.
Write every brief from `references/brief-template.md`: goal, spec, acceptance criteria as commands, where to look, constraints, worktree path, what to return. Done when a stranger with only the repository could start. An external worker cannot ask mid-run: its brief says to return `status: blocked` with precise `questions` on ambiguity.

## 5. Worktree

Every writer gets one: `agent-wt create <task>`. External writer → `--cwd <worktree>` locks it; native writer → `agent-wt lock <task>` and the path in the brief. One writer per worktree. The worktree branches from **HEAD**: uncommitted work is invisible to the workerif `git status` is dirty and the task touches it, tell the user and commit or stash first.
Every writer gets one: `agent-wt create <task>`. External writer → `--cwd <worktree>` locks it; native writer → `agent-wt lock <task>` and the path in the brief. One writer per worktree. The worktree branches from **HEAD**, so uncommitted work is invisible to the worker: if the tree is dirty and the task touches it, tell the user and commit or stash first.

## 6. Review

The author of a non-trivial change does not certify it. A review is **independent** when a fresh read-only worker gets the frozen diff and the spec. Independence, in order of preference:
The author of a non-trivial change does not certify it. A review is **independent** when a fresh read-only worker gets the frozen diff and the spec. Independence, by preference:

1. **the other family** than the author — `route` picks it when that family's CLI is installed;
2. **a fresh worker of the author's family** — what `route` returns when the other CLI is missing (`independent: false`, with a note). Report which one ran.
2. **a fresh worker of the author's family** — `route`'s answer when the other CLI is missing (`independent: false`). Report which one ran.

Review when: any delegated implementation; any change in a risk zone (auth, payments, migrations, prod config); a coordinator-written diff > ~50 lines; the user asks. Freeze and size it:
Review when: any delegated implementation; a risk zone (auth, payments, migrations, prod config); a coordinator-written diff > ~50 lines; the user asks. Freeze and size it:

```
agent-wt diff <task> > review.diff
Expand All @@ -64,20 +64,20 @@ agent-run route --role reviewer --diff review.diff [--author-backend self]

`single` runs straight away. `panel` / `led` are **proposed with the printed numbers and run on the user's yes**. Reviewers run in parallel and blind to each other; merge by `references/review.md`.

**Findings.** Mechanical ones the coordinator fixes. Substantive ones go back to the same implementer (`agent-run resume <id>`, or continue the native subagent). A dispute is settled by a command first — a test, a typecheck, `npm ls`, a grep; spend a **verifier** only on intent, severity or design. A behavior-changing fix re-runs the affected checks and review.
**Findings.** Mechanical ones the coordinator fixes. Substantive ones go back to the same implementer (`agent-run resume <id>`, or continue the native subagent). A dispute is settled by a command first — a test, a typecheck, a grep; a **verifier** only for intent, severity or design. A behavior-changing fix re-runs the affected checks and review.

## 7. Integrate and report

Merge or open a PR per repo conventions; `agent-wt release <task>`, `agent-wt remove <task>`. Report: what was done, what was checked, what was not, open questions, which preset ran, which family reviewed at which depth. A check that did not run is reported as not run; a worker's "done" is evidence to inspect.
Merge or open a PR per repo conventions; `agent-wt release <task>`, `agent-wt remove <task>`. Report: done, checked, not checked, open questions, which preset ran, which family reviewed at which depth. A check that did not run is reported as not run; a worker's "done" is evidence to inspect.

When the brief came from a ticket: once the acceptance commands have run in the coordinator's own hands, tick the ticket's checkboxes and set `Status: done`. The report then ends with the frontier — `closed X of Y, next: <ticket>` — so the ticket files and the answer never disagree.
A ticket's brief: once the coordinator itself has run the acceptance commands, tick its checkboxes and set `Status: done`. The report ends with the frontier — `closed X of Y, next: <ticket>` — so tickets and answer never disagree.

## 8. Handoff

Switching machine, harness or model family mid-task: write `.scratch/handoff/<YYYY-MM-DD>-<task>.md` — where the work stands, what is blocked and on whom, which skills the next session should call, and pointers (spec, tickets, commits, diffs) instead of copies of them. No secrets. The next session starts from that file plus the tickets directory. A handoff transfers ownership; nothing comes back to integrate.
Switching machine, harness or model family mid-task: write `.scratch/handoff/<YYYY-MM-DD>-<task>.md` — where the work stands, what is blocked and on whom, which skills to call next, and pointers (spec, tickets, commits, diffs) instead of copies. No secrets. The next session starts from that file and the tickets. A handoff transfers ownership; nothing comes back to integrate.

## Worker contract

Every worker returns one JSON object (`references/result-schema.json`): `status` (`done` | `blocked` | `failed`), `summary`, `changes`, `checks_run`, `not_verified`, `findings`, `plan`, `questions`, `sources`, `next_steps`. `blocked` + `questions` → the coordinator asks the user and resumes the same worker.
Every worker returns one JSON object per `references/result-schema.json`; `status` is `done` | `blocked` | `failed`. `blocked` + `questions` → the coordinator asks the user and resumes the same worker.

Roles, models and prompt hints: `references/roles.md`. Native definitions: `agents/dk-*.md` (Claude Code) and `references/codex-agents.toml` (Codex), installed by `hooks/install.sh`. `--help` on `scripts/agent-run` and `scripts/agent-wt` is the flag reference.
Roles, models and prompt hints: `references/roles.md`. Native definitions: `agents/dk-*.md` (Claude Code), `references/codex-agents.toml` (Codex), installed by `hooks/install.sh`. `--help` on both scripts is the flag reference.
1 change: 1 addition & 0 deletions skills/delegate-kit/references/external.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ Per-role defaults for one user, in the same file — the shipped table in `scrip
## Limits and safety

- **Delegation depth is 1.** `agent-run` disables subagents on both CLIs; the shipped `dk-*` definitions carry no `Agent` tool.
- **Writer cap 3, ceiling 8; workers = writers + 3**, so a `panel` or `led` review fits beside a full set of writers. `agent-run run` counts external writers machine-wide plus the native locks (`agent-wt lock`) of the repository it writes into; `agent-wt lock` counts the locked worktrees of its repository. The cap is raised per task: the coordinator states the **partition** — one ticket per writer, disjoint write scopes — the user says yes, and `--max-writers N` on the run or the lock carries it (`DELEGATE_KIT_MAX_WRITERS` for the session; `DELEGATE_KIT_MAX_WORKERS` overrides the total, floored at writers + 1). The ceiling holds against every override; past it the work goes in waves. A run refused by a cap or a locked worktree fails before anything is spawned, `--detach` included: the parent prints the reason. A refusal that lands inside the supervisor (a race) is recorded as `failed`, so `status` shows it. Counting and taking a slot happen under one mutex, so concurrent starts respect the cap too. N sessions on one subscription hit the rate limit together; `--fallback none` keeps a fleet from all retrying on the other family at once.
- **Writers** run in a worktree under the backend's own sandbox (`workspace-write` / `acceptEdits`); the dangerous modes are outside this skill. `agent-run` refuses a worktree locked for a native writer, and the reverse.
- **Read-only roles** run under `codex -s read-only` / `claude --permission-mode plan` — the enforced boundary a native role lacks. When it matters (an untrusted diff, a risk zone), dispatch that role externally even inside the family.
- **Quota fallback.** On a usage or rate limit `agent-run` retries the brief once on the other family and marks the result `fallback_from`. For a reviewer that can land the review on the author's family — the result says so; report it or re-run later. `--fallback none` disables it; resumes never fall back.
Expand Down
Loading
Loading