This commit is contained in:
2026-07-10 17:39:32 -07:00
parent 0b2f91ee8e
commit 26abc5357c
352 changed files with 375 additions and 49734 deletions
+105
View File
@@ -0,0 +1,105 @@
---
name: delegate
description: Delegate self-contained tasks to Claude or Codex subagents run as fresh CLI processes. Use proactively, without being asked, whenever work can be handed off — parallel research or code searches, bounded implementation chunks, independent reviews, second implementations for comparison. Pick the provider (Claude, Codex, or both) and tier that best fit each task. Not for consultations the user explicitly routed to a specific peer (use peer-consult for that).
---
# Delegate
Hand a self-contained task to a fresh Claude or Codex subagent and get back a
structured report. Each invocation is one subagent; run several in parallel for
independent tasks.
## When to delegate
- Research or code searches whose details you don't need in your own context.
- Bounded implementation chunks that can be specified up front and verified.
- Independent review passes over a diff, file, or subsystem.
- Getting two independent takes by sending the same task to both providers.
Do not delegate work that needs mid-task input from you or the user, or tasks
so small that writing the brief costs more than doing the work.
## Route the task
Classify the smallest adequate tier:
| Tier | Signals | Codex | Claude |
|---|---|---|---|
| `quick` | Narrow, bounded, one component | `gpt-5.6-terra`, medium | `claude-sonnet-4-6`, medium |
| `quick-context` | Still bounded; more context or nuance | `gpt-5.6-terra`, high | `claude-sonnet-5`, high |
| `standard` | Multi-file feature, ordinary design/debugging, meaningful trade-offs | `gpt-5.6-sol`, medium | `claude-opus-4-8`, medium |
| `deep` | Architecture, concurrency, security, broad ambiguity, high-impact choice | `gpt-5.6-sol`, high | `claude-opus-4-8`, high |
Pick the provider by judgment:
- Either provider handles general coding, research, and review well; when the
task has no special pull, prefer the provider you are NOT running as, so the
subagent brings an independent perspective.
- Use **both** (two invocations, same task) when you want independent
perspectives on a risky or ambiguous problem, or when splitting parallel
work across providers to avoid rate-limit contention.
- Honor an explicit user model preference only if it is in the allowed list:
Codex `gpt-5.6-terra`/`gpt-5.6-sol`; Claude
`claude-sonnet-4-6`/`claude-sonnet-5`/`claude-opus-4-8`. Never silently
substitute another model.
Pick the mode:
- `read` (default): research, searches, reviews, second opinions. Subagent
cannot modify files.
- `write`: implementation and refactors. Subagent may edit files and run
commands inside the repo; it will not commit or push unless the task says to.
## Write the brief
The subagent starts with zero context. Write a self-contained task containing:
- The goal and definition of done.
- Relevant paths, symbols, error messages, or raw diff/plan text.
- Constraints (style, APIs to use or avoid, files off-limits).
- For `write` mode: how to verify (build/test commands).
Pass raw evidence; do not tell the subagent the answer you expect.
## Run it
Resolve `<skill-dir>` to the directory containing this `SKILL.md`. Send the
task on stdin; do not interpolate it into the shell command.
```bash
python3 <skill-dir>/scripts/delegate.py \
--provider codex \
--tier standard \
--mode read \
--repo "$PWD" <<'TASK'
<self-contained task brief>
TASK
```
Flags:
- `--provider claude|codex` (required)
- `--tier quick|quick-context|standard|deep` (default `standard`)
- `--mode read|write` (default `read`)
- `--model <approved-model>` for an explicit allowed override
- `--repo <dir>` (default cwd)
- `--timeout <seconds>` (default 1800)
- `--dry-run` to inspect routing and command construction without running
Parallel delegation: launch each invocation as a separate background shell
command, then collect the outputs. Never point two `write`-mode subagents at
overlapping files; split by file/directory or run them sequentially.
## Handle the result
The report ends with Summary / Details / Files changed / Verification / Open
questions sections. Then:
- Treat it as a subagent's claim, not ground truth: spot-check load-bearing
findings, and for `write` mode review the diff (`git diff`) and re-run
verification before building on it.
- Relay the outcome to the user in your own words; credit which provider/model
produced it when it matters.
- On failure, report the provider, model, and exact error. Retry once with the
same route if transient; escalate tier or switch provider only deliberately,
and say you did.
+270
View File
@@ -0,0 +1,270 @@
#!/usr/bin/env python3
"""Delegate a self-contained task to a Claude or Codex subagent."""
import argparse
import os
import shutil
import subprocess
import sys
import tempfile
from dataclasses import dataclass
from pathlib import Path
ALLOWED_MODELS = {
"codex": frozenset({"gpt-5.6-terra", "gpt-5.6-sol"}),
"claude": frozenset(
{"claude-sonnet-4-6", "claude-sonnet-5", "claude-opus-4-8"}
),
}
# tier -> provider -> (model, effort)
ROUTES = {
"quick": {
"codex": ("gpt-5.6-terra", "medium"),
"claude": ("claude-sonnet-4-6", "medium"),
},
"quick-context": {
"codex": ("gpt-5.6-terra", "high"),
"claude": ("claude-sonnet-5", "high"),
},
"standard": {
"codex": ("gpt-5.6-sol", "medium"),
"claude": ("claude-opus-4-8", "medium"),
},
"deep": {
"codex": ("gpt-5.6-sol", "high"),
"claude": ("claude-opus-4-8", "high"),
},
}
READ_ONLY_RULES = """\
Hard constraints:
- You are in read-only mode. Do not modify, create, rename, or delete files.
- Do not commit, branch, push, or contact external systems that change state.
- Base claims on repository evidence. Cite file paths and line numbers."""
WRITE_RULES = """\
Hard constraints:
- Work only inside the given repository directory.
- Do not commit, branch, push, or open pull requests unless the task says to.
- Do not delete or rename files the task does not cover; if something looks
wrong or unexpected, stop and report instead of guessing.
- Verify your work (build, tests, or a targeted check) when feasible."""
REPORT_FORMAT = """\
End your reply with a report containing these sections:
- Summary: what you did or found, in a few sentences.
- Details: key evidence, decisions, or findings, with file:line references.
- Files changed: list each changed file, or "none".
- Verification: what you ran and the outcome, or "not verified" and why.
- Open questions: anything unresolved the caller must decide, or "none"."""
@dataclass(frozen=True)
class Route:
provider: str
model: str
effort: str
def select_route(provider: str, tier: str) -> Route:
if tier not in ROUTES:
raise ValueError(f"Unknown tier: {tier}")
if provider not in ("claude", "codex"):
raise ValueError(f"Unknown provider: {provider}")
model, effort = ROUTES[tier][provider]
return Route(provider, model, effort)
def apply_model_override(route: Route, model: str) -> Route:
if model not in ALLOWED_MODELS[route.provider]:
raise ValueError(f"Model {model!r} is not allowed for {route.provider}")
return Route(route.provider, model, route.effort)
def build_command(
route: Route,
repo: Path,
mode: str,
output_path: Path | None = None,
) -> list[str]:
if route.provider == "codex":
if output_path is None:
raise ValueError("Codex requires an output path")
sandbox = "read-only" if mode == "read" else "workspace-write"
return [
"codex",
"exec",
"--ignore-user-config",
"--model",
route.model,
"--config",
f'model_reasoning_effort="{route.effort}"',
"--config",
'approval_policy="never"',
"--sandbox",
sandbox,
"--ephemeral",
"--skip-git-repo-check",
"--output-last-message",
str(output_path),
"--cd",
str(repo),
"-",
]
command = [
"claude",
"--print",
"--model",
route.model,
"--effort",
route.effort,
"--disable-slash-commands",
"--no-session-persistence",
]
if mode == "read":
command += [
"--permission-mode",
"plan",
"--tools",
"Read,Glob,Grep",
]
else:
command += [
"--permission-mode",
"acceptEdits",
"--tools",
"Read,Glob,Grep,Edit,Write,Bash",
"--allowedTools",
"Edit,Write,Bash",
]
return command
def build_prompt(task: str, route: Route, mode: str) -> str:
rules = READ_ONLY_RULES if mode == "read" else WRITE_RULES
return f"""You are a {route.provider} subagent completing a delegated task \
inside the current repository. Work independently; the caller cannot answer \
questions mid-task. If the task is ambiguous, choose the safest reasonable \
interpretation and note the choice in your report.
{rules}
- Do not delegate further or invoke Claude or Codex recursively.
{REPORT_FORMAT}
Task:
{task.strip()}
"""
def run_delegation(
route: Route,
repo: Path,
prompt: str,
mode: str,
*,
timeout: int = 1800,
) -> str:
if shutil.which(route.provider) is None:
raise RuntimeError(f"Required CLI is not installed: {route.provider}")
with tempfile.TemporaryDirectory(prefix="delegate-") as temp_dir:
output_path = (
Path(temp_dir) / "report.md" if route.provider == "codex" else None
)
command = build_command(route, repo, mode, output_path)
try:
result = subprocess.run(
command,
cwd=repo,
input=prompt,
text=True,
capture_output=True,
timeout=timeout,
check=False,
)
except subprocess.TimeoutExpired as error:
raise RuntimeError(
f"{route.provider} delegation timed out after {timeout}s"
) from error
if result.returncode != 0:
detail = (result.stderr or result.stdout).strip() or "no error output"
raise RuntimeError(
f"{route.provider} delegation failed ({result.returncode}): {detail}"
)
if route.provider == "codex":
if output_path is None or not output_path.is_file():
raise RuntimeError("Codex did not produce a report")
report = output_path.read_text().strip()
else:
report = result.stdout.strip()
if not report:
raise RuntimeError(f"{route.provider} returned an empty report")
return report
def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
parser = argparse.ArgumentParser(
description="Delegate a self-contained task to a Claude or Codex subagent."
)
parser.add_argument("--provider", choices=("claude", "codex"), required=True)
parser.add_argument(
"--tier",
choices=("quick", "quick-context", "standard", "deep"),
default="standard",
)
parser.add_argument("--mode", choices=("read", "write"), default="read")
parser.add_argument("--model", help="Approved model override")
parser.add_argument("--repo", type=Path, default=Path.cwd())
parser.add_argument("--timeout", type=int, default=1800)
parser.add_argument("--dry-run", action="store_true")
return parser.parse_args(argv)
def main(argv: list[str] | None = None) -> int:
args = parse_args(argv)
try:
task = sys.stdin.read().strip()
if not task:
raise ValueError("Task must be provided on stdin")
repo = args.repo.expanduser().resolve()
if not repo.is_dir():
raise ValueError(f"Repository directory does not exist: {repo}")
route = select_route(args.provider, args.tier)
if args.model:
route = apply_model_override(route, args.model)
prompt = build_prompt(task, route, args.mode)
if args.dry_run:
output_path = (
Path(tempfile.gettempdir()) / "delegate-dry-run-report.md"
if route.provider == "codex"
else None
)
command = build_command(route, repo, args.mode, output_path)
print(f"provider: {route.provider}")
print(f"model: {route.model}")
print(f"effort: {route.effort}")
print(f"mode: {args.mode}")
print(f"command: {' '.join(command)}")
print(f"prompt:\n{prompt}")
return 0
report = run_delegation(
route,
repo,
prompt,
args.mode,
timeout=args.timeout,
)
print(f"[{route.provider} · {route.model} · {route.effort} · {args.mode}]")
print(report)
return 0
except (OSError, RuntimeError, ValueError) as error:
print(f"delegate: error: {error}", file=sys.stderr)
return 2
if __name__ == "__main__":
raise SystemExit(main())