subtask
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| CODEX_HOME | No | Explicit Codex home directory; takes precedence. | |
| SUBTASK_HOME | No | Directory for jobs, worktrees, ledger, and telemetry. | ~/.local/share/subtask |
| SUBTASK_ROUTING | No | Path to routing configuration (weights, "mode": "legacy"). | ~/.config/subtask/routing.json |
| SUBTASK_ENV_FILE | No | Path to the environment file. | ~/.config/subtask/env |
| ANTHROPIC_API_KEY | No | API key used by API engines, read from ~/.config/subtask/env. | |
| SUBTASK_MAX_JOB_USD | No | Maximum spend per job in USD. | 20 |
| SUBTASK_MAX_RUNNING | No | Maximum number of running jobs globally across all processes. | 4 |
| SUBTASK_CODEX_JOB_HOME | No | Directory for Codex job home; used if it has config.toml, otherwise a sanitized ~/.codex-jobs is prepared. | ~/.codex-job |
| SUBTASK_CODEX_KEEP_MCP | No | Set to keep the normal Codex home and its MCP servers. | |
| SUBTASK_PROGRESS_MIN_S | No | Minimum interval in seconds for progress updates. | 2 |
| SUBTASK_TELEMETRY_DAYS | No | Number of days to retain telemetry data. | 90 |
| SUBTASK_DEFAULT_MAX_USD | No | Default maximum spend per job in USD. | 2 |
| SUBTASK_MONTHLY_CAP_USD | No | Monthly spending cap in USD. | 180 |
| SUBTASK_JOB_RETENTION_DAYS | No | Number of days to retain job data. | 30 |
| SUBTASK_PROGRESS_HEARTBEAT_S | No | Heartbeat interval in seconds for progress updates. | 10 |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
Delegate long work to cheap engines; do small edits yourself (small tasks cost 2-3x).
Pattern: ONE start_many([...]) for every job, ONE wait(ids) (blocking; ends with batch or first
job, mode='any'). Never poll status(). Codex 0.164.0 cannot wake an idle turn from MCP
notifications: keep wait(ids, mode='any', timeout=60, since='') open, drop ended ids and pass
back cursor=. Never sleep 600 and check later.
result(id, full/evidence) or inspect(id, tail, grep) only if the summary is not enough.
Context: never paste files/diffs into task; use context_refs=['file:p.py:10-80','git:diff',
'subtask::summary'] and auto_repomap=True; files=[...] for paths.
Writes: isolation='worktree' (or repo=) plus verify='pytest -q ...'; invariants on
(no deleted/skipped tests, no new noqa/type: ignore), allowed_paths=[...] reverts the rest.
Several jobs on one Python file: symbol_scope=['f.py::func'].
Review: integrate(ids, action='diff') before action='apply'; apply is all or nothing.
Jev: jev() reads policy; only the operator changes auto/manual/off. Read the automatic outcome in
wait() before any manual review; do not submit it again. supported is advice, not acceptance;
scope unproven is not a pass. Local checks stay mandatory. review(id, criteria,
original_request=...) judges full scope; submit=True spends the budget. Keys only via
subtask jev setup; key/budget errors and unknown sends are never retried.
Pick the tool:
steps that depend on each other -> start_many with id + depends_on; foreach= fans out over
.subtask/fanout.json (max 8); after='any' joins on the first success.
the same edit over many files -> map_reduce, not many start calls.
a regression somewhere in git history -> bisect(good_ref, bad_ref, test_cmd).
check behavior or speed -> oracle_cmd on start.
a critical bug or design doubt -> consensus(prompt, engines) or wait(mode='first_success').
a job stalled or going wrong -> steer(id, 'hint'|'abort'|'retry', instruction).
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": false
} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| planA | Preview tasks before workers start. Read deterministic facts and advisory Jev contradictions, then launch=True with plan_id to start the unchanged plan once. Changed inputs require a new preview. This is a coordinator decision within the authorized task, not a new operator permission. Legacy start/start_many remain available. Read dependencies must be explicit in depends_on. |
| startA | Start one job; returns its id. kind: read|code|review|hard. Writes: repo= or isolation='worktree' (own branch). model: engine-specific model id (opencode, codex, kimi, API engines); omitted = the engine's default. verify: shell check run by subtask after the job; max_retries (0-5) resumes with the failure. invariants: default ['no_test_deletion','no_suppression'] fail verify on deleted/skipped tests or new noqa; [] = off. allowed_paths: files outside are reverted. symbol_scope: ['f.py::func'] only those defs may change; integrate merges by symbol. oracle_cmd: after verify passes, run on base and result; reports output_match and speedup_pct. adversarial: a Breaker job writes the tests first. context_refs: file:P[:A-B] | git:diff[:REF] | subtask:ID:summary|diff instead of pasting text; auto_repomap adds a symbol map. policy: worktree|sandbox|isolated|untrusted. tier: auto|fast|balanced|deep|free_only. |
| start_manyA | Start several jobs in one call. Items take start()'s arguments. With id + depends_on they form a group (grp-…) run as a DAG; subtask::summary in task/context_refs is replaced by the real job id. With Jev auto, the response includes advisory dependency checks; read them without treating them as permission. foreach=: one copy per item of the JSON list the parent writes to .subtask/fanout.json ({{item}} in task), max 8; dependents wait for every copy. after='any': start when one parent succeeded. |
| waitA | Block until jobs or groups end and return their summaries. mode: all | any (first to end) | first_success (first done and verified; the rest are stopped). Returns early on a stalled job. since: cursor for clients without progress; with it, timeout is capped at 60 s. For Codex: wait(ids, mode='any', timeout=60, since=''), drop ended ids and pass back cursor=. An idle Codex 0.164.0 is not woken by ordinary local MCP progress or log notifications. Includes the automatic Jev delivery/evidence/risk advice, raw provider choice, wrapper assessment and next action: read it before a manual review and do not resubmit the same work. |
| statusD | One line per job. |
| resultD | Job summary; full=True for all; evidence=True for the JSON envelope. |
| replyC | Jev auto adds advisory feedback checks; read the output. Continue a finished job. |
| stopC | Stop a job. |
| steerB | Correct a job: hint (instruction sent when the attempt ends) | abort | retry (fresh job with the instruction). |
| jevA | Show or change the shared Jev policy: status | auto | manual | off. Only the operator changes
the policy: do not switch it to obtain or avoid a check. Auto checks every new final delivery once
within the existing budget; read that outcome in wait()/result before any manual review. All advice
is consultative. Credentials are never accepted here: add or replace a key in a terminal with
|
| reviewA | Advisory Jev review of a terminal delivery against the parent's criteria (1-12). Read the
automatic outcome in wait()/result first; do not resubmit the same delivery. Default prepares a
local evidence packet without network; packets=True prepares separate claim packets and manifests
offline (never submits). submit=True sends one request (unknown sends are never
retried). Supply original_request from the coordinator to judge full scope; without it
scope_assessment is unproven, which is neither a pass nor a contradiction. supported is advice,
not acceptance. provider_choice is the raw answer; assessment includes local vetoes (missing,
failed or mismatched evidence), which are not findings by the model. Jev never accepts, merges,
deploys or retries the worker; local checks remain necessary. Key/budget errors are final for the
call: keys only from |
| inspectA | Raw log lines of a job (last |
| integrateA | Bring worktree jobs back. diff first to review; apply = uncommitted, all or nothing, Python files of symbol_scope jobs merged by symbol; discard removes worktree and branch. auto_resolve: a reconcile job on conflict. |
| bisectC | First commit in good_ref..bad_ref that fails test_cmd, testing up to parallelism commits at once. auto_fix: start a fix job. |
| consensusB | 2-4 engines solve prompt blind in worktrees, then one job merges the best (verify, invariants). Returns a group id for wait(). |
| map_reduceB | The same edit over many files: one job per batch of files matching glob ({{files}} in prompt_template),
at most |
| cleanupB | Remove a job's worktree, keep branch. |
| enginesC | Free quota and API spend. |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
TDQS
Scored across 18 tools
Most tools target distinct workflow stages, but several boundaries blur: plan versus start/start_many, status versus result/wait/inspect, cleanup versus integrate discard, and general start_many versus specialized consensus/map_reduce. The detailed descriptions help, but an agent could still misselect among orchestration and monitoring tools.
All names are lowercase snake_case, which is readable, but the convention mixes bare verbs (start, wait, stop, steer) with nouns (status, result, jev, consensus, engines) and does not follow a predictable verb_noun pattern. Two snake_case compound names exist, but semantic naming is inconsistent.
Eighteen tools is slightly above the typical well-scoped range, but the server supports a complex orchestration domain with jobs, worktrees, reviews, and specialized workflows. The count is reasonable and most tools appear to earn their place.
The surface covers job creation, monitoring, steering, stopping, cleanup, integration, review, policy, bisect, consensus, map_reduce, and quota. Minor gaps exist, such as unclear explicit job deletion or group cancellation semantics, but core lifecycle workflows are represented.