[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6N0AMFSRMB6A4M53BZVREVJ":3,"skill-same:01M6N0AMFSRMB6A4M53BZVREVJ":131},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":23,"publishedAt":56,"linkOnly":57,"markdownContent":58,"markdownBody":59,"frontMatter":60,"refName":103,"commitSha":104,"skillDirectory":105,"forksCount":106,"repositoryHtmlUrl":107,"repositoryHomepageUrl":6,"ownerHtmlUrl":108,"ownerBlogUrl":109,"ownerDescription":110,"updatedAt":111,"install":112,"resources":124},"01M6N0AMFSRMB6A4M53BZVREVJ","minion-orchestrator",null,"Unified Minions skill for both deterministic shell jobs and LLM subagent\norchestration. Replaces the older `gbrain-jobs` routing intent. Use when:\nsubmitting gbrain jobs, shell\u002Fbackground tasks, spawning subagents,\nchecking progress, steering running work, pausing\u002Fresuming, parallel\nfan-out. One durable, observable, steerable queue interface. Also carries\nthe durable-execution doctrine for any operation expected to exceed ~2\nminutes: capability ladder, deadman checks that verify the result was\nreported, and content-addressed stage checkpoints for expensive pipelines.","garrytan\u002Fgbrain","garrytan","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F19957?v=4","01M6DJCCDDG53MTYYRTXAXFG17","Garry Tan","01M6MZQZCEN3RRMD33E1X9ZZR9",32762,"MIT","https:\u002F\u002Fgithub.com\u002Fgarrytan\u002Fgbrain\u002Fblob\u002Fmaster\u002Fplugin\u002Fskills\u002Fminion-orchestrator\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55],"minion orchestrator","orchestrator","do","doctrine","message","get","progress","submit","direction","spawn agent","interface","for","shell command","pause","send","capability","result","orchestration","intent","stop","use","subagents","spawn","list","command","work","parallel","subagent","pipeline","run","tasks","change","2026-11-10 10:12:30",false,"---\nname: minion-orchestrator\nversion: 1.1.0\ndescription: |\n  Unified Minions skill for both deterministic shell jobs and LLM subagent\n  orchestration. Replaces the older `gbrain-jobs` routing intent. Use when:\n  submitting gbrain jobs, shell\u002Fbackground tasks, spawning subagents,\n  checking progress, steering running work, pausing\u002Fresuming, parallel\n  fan-out. One durable, observable, steerable queue interface. Also carries\n  the durable-execution doctrine for any operation expected to exceed ~2\n  minutes: capability ladder, deadman checks that verify the result was\n  reported, and content-addressed stage checkpoints for expensive pipelines.\ntriggers:\n  - \"gbrain jobs submit\"\n  - \"submit a gbrain job\"\n  - \"submit a shell job\"\n  - \"shell job\"\n  - \"run shell command in background\"\n  - \"deterministic background task\"\n  - \"spawn agent\"\n  - \"background task\"\n  - \"run in background\"\n  - \"check on agent\"\n  - \"agent progress\"\n  - \"what's running\"\n  - \"steer agent\"\n  - \"change direction\"\n  - \"tell the agent\"\n  - \"pause agent\"\n  - \"stop agent\"\n  - \"resume agent\"\n  - \"parallel tasks\"\n  - \"fan out\"\n  - \"do these in parallel\"\n  - \"long operation\"\n  - \"durable execution\"\n  - \"arm a deadman\"\n  - \"the job went silent\"\n  - \"operation died in the background\"\n  - \"make this pipeline resumable\"\ntools:\n  - submit_job\n  - get_job\n  - list_jobs\n  - cancel_job\n  - pause_job\n  - resume_job\n  - replay_job\n  - send_job_message\n  - get_job_progress\nmutating: true\nupstream: long-ops@fc834ee, subagent-deadman@fc834ee, pipeline-stage-cache@fc834ee\nwhen_to_use: \"Use when the user asks: \\\"gbrain jobs submit\\\", \\\"submit a gbrain job\\\", \\\"submit a shell job\\\", \\\"shell job\\\", \\\"run shell command in background\\\".\"\n---\n\n# Minion Orchestrator\n\n## Contract\n\nMinions is a Postgres-native job queue for durable, observable background work.\nThis single skill handles two lanes:\n- Deterministic shell jobs (`gbrain jobs submit shell ...`)\n- LLM subagent jobs (`gbrain agent run ...`)\n\nWhen to route to Minions: durable, observable work that must survive restarts,\nfan out across many parallel tasks, or persist across sessions. Routing policy\nis defined in `skills\u002Fconventions\u002Fsubagent-routing.md` — the project default is\n`pain_triggered` (native subagents first, Minions after specific pain signals\nfire); Mode A (all-through-Minions) is opt-in.\n\nGuarantees:\n- Jobs survive gateway restart (Postgres-backed)\n- Every job has structured progress, token accounting, and session transcripts\n- Running agents can be steered mid-flight via inbox messages\n- Jobs can be paused, resumed, or cancelled at any time\n- Parent-child DAGs with configurable failure policies\n\nDurable-execution doctrine (routing convention the agent follows — nothing\nmechanically enforces it; see \"Durable execution\" below):\n- Operations expected to exceed ~2 minutes route through the capability\n  ladder, never a bare background shell that dies with the session.\n- A deadman check verifies the result was REPORTED to the user, not merely\n  that the process exited — a swallowed completion event looks identical to\n  a dead job from the user's side.\n- The deadman is second-line insurance, not a delivery guarantee: it can\n  itself die before firing (scheduler restart, deleted entry). Backstop:\n  on the next turn, sweep `gbrain jobs list --status active` and recent\n  completions for overdue work whose result never reached the user.\n- Deadman checks are idempotent. A double-fire, or a fire that races the\n  normal completion report, produces silence — it checks reported-state\n  first and tags any recovery report with the job ID so duplicates are\n  detectable.\n- A checkpoint or progress file is trusted only with a freshness check.\n  A stale checkpoint reads as \"still running\" forever; compare its\n  timestamp against the expected progress interval and against\n  `gbrain jobs get \u003Cid>`.\n\n## Route the Request: Shell Job vs Subagent\n\n| Condition | Action |\n|---|---|\n| User asks for deterministic command\u002Fscript run | Shell job (CLI: `gbrain jobs submit shell ...`) |\n| User asks to \"run in minions\" + explicit command\u002Fargv | Shell job (CLI, `--params` with `cmd` or `argv`) |\n| User asks for research\u002Freasoning\u002Fiterative agent | Subagent job (CLI: `gbrain agent run`) |\n| User asks to steer\u002Fpause\u002Fresume an agent | Subagent job lifecycle tools (MCP-callable) |\n| Single simple operation under ~30s | Consider inline execution first |\n| Needs restart durability\u002Fobservability | Submit as Minion job |\n| Operation expected to exceed ~2 minutes | Route through the Durable execution ladder (below) |\n| Parallel work (2+ streams) | `gbrain agent run --fanout-manifest` or parent + child subagents |\n\nIf intent is ambiguous, ask one clarification:\n\"Do you want a deterministic shell command job, or an LLM agent job?\"\n\n## Shell Jobs (Deterministic Scripts)\n\nUse for reproducible command execution, ETL steps, cron work, and scriptable\ntasks where no LLM reasoning loop is needed.\n\n### Preconditions (read before submitting your first shell job)\n\n- **The worker must be started with `gbrain jobs work --allow-shell-jobs`** (equivalently `GBRAIN_ALLOW_SHELL_JOBS=1` exported on the worker; a `.env` in the worker's directory cannot set it).\n  The shell handler is always registered but guarded: an unflagged worker that\n  claims a shell job dead-letters it immediately (`UnrecoverableError`, straight\n  to `dead`, no retries) with the flag named in `error_text`. A job that sits in\n  `waiting` means NO worker is running at all — check\n  `gbrain jobs supervisor status`. Gate lives in `src\u002Fcore\u002Fminions\u002Fhandlers\u002Fshell.ts`.\n- **Security:** flipping `GBRAIN_ALLOW_SHELL_JOBS=1` authorizes arbitrary\n  command execution on the worker. On a shared queue, this is a remote code\n  execution surface. Treat as privileged infrastructure authorization.\n- **Execution mode — pick one:**\n  - **Postgres + daemon:** `gbrain jobs work` runs a persistent worker that\n    claims and executes jobs from the queue.\n  - **PGLite + --follow:** `gbrain jobs submit ... --follow` runs inline.\n    The daemon mode is not available on PGLite (exclusive file lock). See\n    `docs\u002Fguides\u002Fminions-shell-jobs.md`.\n- **MCP boundary:** shell-job submission is CLI-only. `submit_job name=\"shell\"`\n  over MCP throws an `OperationError` with code `permission_denied`; generic\n  remote submission accepts only `sync`, `import`, `lint`, and `lint-fix`.\n  Agents CAN observe shell jobs via `get_job` \u002F `list_jobs` \u002F `get_job_progress`\n  (not protected), but cannot submit them. Operator or autopilot submits;\n  agent observes.\n- **Verify setup:** after configuration, run `gbrain jobs stats` (CLI) to\n  confirm the worker is registered and consuming the queue.\n\n### Submit (CLI, operator or autopilot)\n\nShell jobs take their command via `--params` as a JSON object with `cmd` (string)\nor `argv` (array), plus `cwd` and optional `env`.\n\nCommand string form:\n```\ngbrain jobs submit shell --params '{\"cmd\":\"echo hello\",\"cwd\":\"\u002Fabs\u002Fpath\"}'\n```\n\nArgv form (no shell expansion):\n```\ngbrain jobs submit shell --params '{\"argv\":[\"bash\",\"-lc\",\"echo hello\"],\"cwd\":\"\u002Fabs\u002Fpath\"}'\n```\n\nInline execution on PGLite or any one-shot deployment:\n```\ngbrain jobs submit shell --params '{\"cmd\":\"echo hello\",\"cwd\":\"\u002Ftmp\"}' --follow\n```\n\nQueue\u002Flifecycle flags exposed by `gbrain jobs submit --help`: `--queue`,\n`--priority`, `--delay`, `--max-attempts`, `--max-stalled`, `--backoff-type`,\n`--backoff-delay`, `--backoff-jitter`, `--timeout-ms`, `--idempotency-key`,\n`--dry-run`.\n\n### Monitor (agents or operator)\n\nThese operations are MCP-callable and safe for agent use:\n\n```\nlist_jobs --name shell --status active\nget_job ID\nget_job_progress ID\n```\n\nCheck structured result fields (exit code, stdout\u002Fstderr tails, attempts,\ntimings) from `get_job`. Use `get_job_stats` (MCP) or `gbrain jobs stats`\n(CLI) for the worker\u002Fqueue health dashboard incl. the wedged-queue signal.\n\n### Control (MCP-callable)\n\n```\ncancel_job id=ID\nreplay_job id=ID\n```\n\n`replay_job` is not protected — only shell *submission* is. Agents can\ncancel or replay a shell job without CLI access.\n\nUse idempotency keys for recurring shell workloads to avoid duplicate runs.\n\n## Subagent Jobs (LLM Orchestration)\n\nUse for open-ended reasoning, tool-using research, and fan-out synthesis.\n\n**User-facing entrypoint:** `gbrain agent run \u003Cprompt>` is the canonical way\nto submit subagent work. It handles the elevated-trust plumbing — `subagent`\nand `subagent_aggregator` are protected job names. Remote agents use the\ndedicated `submit_agent` operation with their configured source, tools, and\nslug binding; generic `submit_job` does not accept these job names.\n\n## Phase 1: Submit\n\n```\ngbrain agent run \"Research Acme Corp revenue\" --tools \"search,query\"\n```\n\n`--tools` accepts a comma-separated subset of `BRAIN_TOOL_ALLOWLIST` (see\n`src\u002Fcore\u002Fminions\u002Ftools\u002Fbrain-allowlist.ts`): `query`, `search`, `get_page`,\n`list_pages`, `get_backlinks`, `traverse_graph`, `list_link_sources`,\n`resolve_slugs`, `get_ingest_log`, `put_page`, `add_timeline_entry`,\n`get_recent_salience`, `find_anomalies`. Attachment tools and local-only\noperations are unavailable. Update old bindings before resubmitting jobs\nthat reference removed tools. Remote bindings must be nonempty; an explicit\nempty local tool list grants no tools.\n\nFor parallel work with a fan-out manifest:\n```\ngbrain agent run --fanout-manifest companies.json\n```\n\nThe manifest describes N children + 1 aggregator. Each child runs\n`name=\"subagent\"` under the hood; the aggregator runs `name=\"subagent_aggregator\"`\nand claims AFTER every child terminates. See\n`src\u002Fcore\u002Fminions\u002Fhandlers\u002Fsubagent.ts` and\n`src\u002Fcore\u002Fminions\u002Fhandlers\u002Fsubagent-aggregator.ts`.\n\nFlags (from `src\u002Fcommands\u002Fagent.ts`):\n- `--subagent-def \u003Cname>` — named subagent definition\n- `--model \u003Cid>` — override model\n- `--max-turns \u003CN>` — cap the LLM loop\n- `--tools \u003Ccsv>` — allow-listed brain tools (see above)\n- `--timeout-ms \u003CN>` — hard timeout per job\n- `--fanout-manifest \u003Cfile>` — N children + 1 aggregator\n- `--follow` \u002F `--no-follow` — stream logs + wait (default on TTY)\n- `--detach` — submit and return immediately\n\nQueue\u002Fpriority\u002Fretry tuning is not exposed by `gbrain agent run`; submit the\nraw `subagent` handler via `gbrain jobs submit` (requires CLI trust) if you\nneed those knobs.\n\n**Admission control (v0.46.11.0).** Identical parentless `subagent` submits\n(same owner lane, payload, and execution options) coalesce onto the existing\nwaiting job: `gbrain agent run` prints `coalesced` with the matched job id,\nand the `submit_agent` MCP response carries `coalesced: true`. Treat that as\nsuccess — monitor the matched id, do NOT resubmit. Jobs still waiting after\nthe TTL (48h default for `subagent`; `minions.ttl_waiting_hours.\u003Cname>`)\nare cancelled with reason prefix `waiting_ttl_expired`. If an operator has\nconfigured a waiting quota (`minions.quota_max_waiting.\u003Cname>`), a submit\npast the cap returns a structured, retryable `rate_limited` error — back\noff and check `gbrain jobs stats` for a `DIVERGENT QUEUE` line before\nretrying.\n\n## Phase 2: Monitor\n\n```\nlist_jobs --status active          # MCP — what's running?\nget_job ID                         # MCP — full details + logs + tokens\nget_job_progress ID                # MCP — structured progress snapshot\ngbrain jobs stats                  # CLI — queue health dashboard\ngbrain agent logs ID --follow      # CLI — streaming transcript + heartbeat\n```\n\nProgress includes: step count, total steps, message, token usage, last tool called.\n\n## Phase 3: Steer\n\nSend a message to redirect a running agent:\n```\nsend_job_message id=ID payload={\"directive\":\"focus on revenue, skip headcount\"}\n```\n\nThe agent handler reads inbox messages on each iteration and injects them as\ncontext. Messages are acknowledged (read receipts tracked).\n\nOnly the parent job or admin can send messages (sender validation).\n\n## Phase 4: Lifecycle\n\n```\npause_job id=ID                    # freeze without losing state\nresume_job id=ID                   # pick up where it left off\ncancel_job id=ID                   # hard stop\nreplay_job id=ID                   # re-run with same or modified params\nreplay_job id=ID data_overrides={\"depth\":\"deep\"}  # replay with changes\n```\n\nAll lifecycle ops are MCP-callable.\n\n## Phase 5: Review Results\n\n```\nget_job ID                         # result, token counts, transcript\n```\n\nToken accounting: every job tracks `tokens_input`, `tokens_output`, `tokens_cache_read`.\nChild tokens roll up to parent automatically on completion.\n\n## Durable execution (operations >2 minutes)\n\nBackground shells die silently: session compaction, harness restart, tool\ntimeout. Long gbrain operations (`extract all`, `embed --stale`, a full\n`sync --all`) routinely run 10-60 minutes — past every one of those\nceilings. And even when the work survives, the *completion event* can be\nswallowed (worker restart, dropped notification), leaving the user staring\nat silence while a finished result sits unreported. Durable execution\ncovers both halves: the work survives, and the report provably lands.\n\nRoute any operation expected to exceed ~2 minutes through the **highest\nrung of this ladder the deployment supports**. This is a harness-routing\nconvention the agent follows, not a mechanical guarantee — nothing stops a\nbare background shell except this skill saying don't.\n\n**Paid work gets consent before it is submitted.** A job runs without a\nterminal, so a paid command (`embed --stale`, or anything else that calls a\nmodel provider) stops with exit 3 and a consent payload unless it already\ncarries the user's approval. Get that approval first, in the conversation:\nrun the command's preview (for example `gbrain embed --stale --dry-run`),\nrelay the estimate, and only after the user agrees put the approval in the\nsubmitted command (`gbrain embed --stale --yes --max-usd \u003Ccap>` with the cap\nthey approved), or rely on a standing approval the user set with\n`gbrain config set consent.preapprove.paid.max_usd_per_run \u003Cusd>`. Never add\n`--yes` without the user's answer. When a job ends with exit 3 or the\n`confirmation_required` code, relay its message to the\nuser and stop; don't resubmit it with `--yes`.\n\n### Rung 1 — Minion job + deadman (Postgres + worker)\n\nRequires: Postgres engine, a running `gbrain jobs work` worker, and — for\nthe shell lane — a worker started with `--allow-shell-jobs` (or\n`GBRAIN_ALLOW_SHELL_JOBS=1` exported on it). All the\nPreconditions above still hold: the flag defaults OFF, shell submission is\nCLI-only across the MCP trust boundary, and PGLite has no worker daemon\n(see Rung 3). Nothing in this section loosens that contract.\n\n1. **Submit as a job** so the work survives restarts:\n\n   ```\n   gbrain jobs submit shell \\\n     --timeout-ms 3600000 \\\n     --params '{\"cmd\":\"gbrain extract all\",\"cwd\":\"\u002Fabs\u002Fpath\",\"inherit\":[\"database_url\"]}'\n   ```\n\n   Work that needs LLM judgment goes through the subagent lane\n   (`gbrain agent run`, above) instead — a submitted agent job you never\n   check on is the same bug as an unwatched shell job.\n\n2. **Arm a deadman in the same action block** (pattern below). Submitting\n   without arming is the classic half-fix: the job survives, the silence\n   doesn't.\n\n### Rung 2 — cron-checked progress file (no agent-waking scheduler)\n\nWhen no scheduler can wake the agent but the host has a plain crontab (or\nthe work runs outside the queue entirely): make the operation write a\nprogress\u002Fheartbeat file as it advances (or rely on `get_job_progress` for\nqueue jobs), and register a recurring host-cron check that compares the\nfile's freshness against the expected progress interval. The agent also\nchecks it at the start of the next turn. A checkpoint that stops advancing\nmeans **stalled**, not \"still running\" — the freshness comparison is the\nentire value of this rung.\n\n### Rung 3 — foreground + output buffering (PGLite \u002F no worker \u002F no scheduler)\n\nRun the operation inline in the foreground — on PGLite that's\n`gbrain jobs submit ... --follow`, or just the raw command — and buffer\nall output to a file, reading bounded slices, per\n`skills\u002Fconventions\u002Fexec-output.md`. An empty tool result after a long\ncommand is truncation, not a dead shell. This rung has no silent-death\ninsurance, so keep the operation in the foreground and stay with it;\nbackgrounding here recreates the exact failure the ladder exists to\nprevent.\n\n### The deadman pattern\n\nA one-shot, self-deleting scheduled check that fires at\nexpected-finish-plus-margin and verifies the **result was reported** — not\njust that the process exited. Arm it **in the same action block as the\nsubmission** (not after, not \"if I remember\").\n\n1. Estimate `expected_minutes` honestly; round up.\n2. Deadline = now + estimate + margin, where `margin = max(10 min, 50% of\n   estimate)`. Restarts delay delivery — too tight false-fires, hours-late\n   defeats the point.\n3. Create the check with whatever one-shot scheduler the host offers: a\n   harness cron tool with delete-after-run semantics, `at`, or a crontab\n   entry the check removes on first fire. The check's instruction:\n   - Verify the result was **already reported to the user**. `gbrain jobs\n     get \u003Cid>` gives the job state; the reported-check asks whether a\n     completion message actually reached the user.\n   - **Reported** → do nothing, stay silent, self-delete.\n   - **Completed but unreported** (swallowed event) → pull the result via\n     `gbrain jobs get \u003Cid>` and post the recovery report now, tagged with\n     the job ID.\n   - **Still running** → post a one-line status with a new ETA and arm ONE\n     follow-up deadman at +50% of the original estimate. One follow-up\n     max — no infinite chains.\n   - **Dead\u002Ffailed** → report what it produced before dying (`stderr_tail`\n     from `gbrain jobs get \u003Cid>`) and offer `gbrain jobs retry \u003Cid>`.\n4. **Disarm on normal completion.** When the completion arrives and you\n   report it, remove the deadman. If it fires anyway, the reported-check\n   makes it a silent no-op — belt and suspenders.\n\nFailure modes the pattern must own (mirrored in Contract and\nAnti-Patterns): the deadman itself dying before it fires (second-line\ninsurance, backstopped by the next-turn overdue sweep), double-fire\n(idempotent reported-check + job-ID-tagged reports), and stale checkpoints\n(freshness check before trusting \"still running\").\n\nEval contract, imported with the pattern — a deadman deployment is judged\non:\n\n- **ARMED_ON_SPAWN** — created in the same action block as the long\n  submission?\n- **SELF_DELETING** — one-shot, and silent when all is well?\n- **DETECTS_SWALLOWED** — verifies the result was reported, not just that\n  the job exited?\n- **RECOVERS** — on a swallowed event, pulls the output and posts the\n  recovery report?\n- **RIGHT_DEADLINE** — expected finish + sane margin, neither false-firing\n  nor hours late?\n\nHard fails: a long user-facing operation with no deadman armed; a deadman\nthat posts noise when the completion arrived normally; emulating the timer\nwith `sleep` or a poll loop instead of a scheduler entry (a sleeping\nprocess dies with the session — the exact failure being insured against).\n\n### Sequencing and locks\n\nMaintenance operations share locks (`sync`, `embed`, `extract`,\n`integrity`). Run them **sequentially, chained**: submit job 1, arm its\ndeadman; on completion, submit job 2, arm the next; finish with\n`gbrain doctor` and report the health delta. If a job dies mid-operation\nits lock expires at TTL (a live, recently-refreshed holder is protected by\nthe steal grace) — never hand-delete lock rows to \"unstick\" a queue.\n\n### Typical long operations\n\nDurations scale with corpus size; treat these as order-of-magnitude\nanchors for `--timeout-ms`, not promises.\n\n| Operation | Typical duration | Suggested `--timeout-ms` |\n|---|---|---|\n| `extract all` | 30-60 min on large brains | 3600000 |\n| `embed --stale` | 5-30 min (scales with missing count) | 1800000 |\n| `sync --all` | 5-20 min | 1200000 |\n| `integrity auto` | 10-30 min | 1800000 |\n| `dream` | 5-15 min | 900000 |\n\n### Appendix: content-addressed stage checkpoints\n\nFor a multi-stage pipeline with an expensive middle (extract → score →\nexplain → render → verify, where the scoring stage burns real LLM spend),\nmake each stage a content-addressed checkpoint so a crash — or a\ndeadman-triggered retry, or a `replay_job` — **resumes** instead of\nre-spending:\n\n- **Key each stage** on a hash of (the stage's own logic + its params +\n  the hashes of its upstream artifacts). Store artifacts under a `.cache\u002F`\n  directory in the pipeline's working tree, addressed by content hash.\n- **Warm re-run is a no-op**: every key matches, nothing recomputes, the\n  whole pipeline replays in well under a second.\n- **Busting cascades correctly**: a param change or a logic edit changes\n  that stage's key, recomputing it and every downstream stage whose\n  upstream hashes changed. The stage's own source must be part of the\n  key — omit it and logic edits silently reuse stale artifacts.\n- **Record provenance**: a provenance file per run records each stage's\n  key, inputs, outputs, and computed-at, so every artifact traces to the\n  exact logic + data that produced it and \"which stage recomputed and\n  why\" stays answerable.\n- **Verify integrity on restore**: check live artifacts against recorded\n  checksums; a mismatch means recompute or restore from cache, never\n  silent reuse.\n\nJudged on: **IDEMPOTENT** (warm re-run recomputes nothing),\n**CORRECT_BUSTING** (a change recomputes exactly the affected stages),\n**PROVENANCE** (every artifact traces to logic + params + upstreams),\n**INTEGRITY** (corrupted artifacts detected, never silently reused).\n\nThis composes with the ladder rather than replacing it: the ladder keeps\nthe pipeline running and reported; stage checkpoints keep a retry cheap.\nPair them whenever a single stage costs more than pocket change in LLM\nspend.\n\n## Output Format\n\nWhen reporting job status to the user:\n\n```\nJob #ID (name) — status\nProgress: step\u002Ftotal — last action\nTokens: input_count in \u002F output_count out (+ cache_read cached)\nRuntime: Xs\nChildren: N pending, M completed\n```\n\nWhen reporting completion:\n\n```\nJob #ID completed in Xs\nTokens used: input \u002F output \u002F cache_read\nResult: \u003Csummary>\n```\n\nWhen reporting batch status (parent with children):\n\n```\nParent #ID — waiting-children\n  #A subagent(Acme) — active, 3\u002F5 steps, 2.5k tokens\n  #B subagent(Beta) — completed, 1.8k tokens\n  #C subagent(Gamma) — paused\nTotal tokens so far: 4.3k\n```\n\n## When it fails\n\nFollow the [agent operator protocol](..\u002Fconventions\u002Fagent-operator-protocol.md) for any gbrain error `code`, exit code, `[AGENT]` block or notice block. Specific to this skill:\n\n- `gbrain jobs submit` over MCP for a protected job returns `permission_denied`: it must run from the trusted local CLI on the brain host; tell the user.\n- A shell job dead-letters immediately with the flag named in `error_text` (shell jobs disabled): tell the user which env flag the host operator must set; do not retry.\n- `rate_limited` from the submission cap: back off for the stated delay before resubmitting; do not fan out more submissions meanwhile.\n- A job sits in `waiting` with no worker: confirm a worker is registered (`gbrain jobs get \u003Cid>`) before resubmitting.\n\n## Anti-Patterns\n\n- Don't spawn a Minion for a single search query (use search tool directly)\n- Don't fire-and-forget without checking results\n- Don't spawn > 5 concurrent agents without checking `gbrain jobs stats` first\n- Don't resubmit when a submit reports `coalesced` — the work is already queued; monitor the matched job id instead\n- For subagent work, don't use `sessions_spawn` with `runtime: \"subagent\"` when Minions is available (use `gbrain agent run` instead)\n- Don't poll `get_job` in a tight loop (use `get_job_progress` for lightweight checks)\n- Don't run an operation expected to exceed ~2 minutes as a bare background shell — it dies with the session; route through the Durable execution ladder\n- Don't say \"I'll report back when it finishes\" without an armed deadman or a scheduled check that will actually fire\n- Don't let a deadman post noise when the completion arrived normally — check reported-state first, stay silent, self-delete\n- Don't emulate the deadman timer with `sleep` or a poll loop — a sleeping process dies with the session, which is the exact failure being insured against\n- Don't trust a checkpoint or progress file without a freshness check — a stale checkpoint reads as \"still running\" forever\n- Don't run lock-acquiring maintenance ops (`sync`, `embed`, `extract`, `integrity`) simultaneously, and don't hand-delete lock rows to unstick them (locks expire at TTL)\n\n## Tools Used\n\n- Submit a background job — `submit_job` (MCP: only `sync`, `import`, `lint`, and `lint-fix`, under the contract in `docs\u002Fguides\u002Fauthorization-upgrade.md`; shell jobs use the local CLI, remote subagents use `submit_agent`)\n- Get job details — `get_job` (MCP)\n- List jobs with filters — `list_jobs` (MCP)\n- Cancel a job — `cancel_job` (MCP)\n- Pause a job — `pause_job` (MCP)\n- Resume a paused job — `resume_job` (MCP)\n- Replay a completed\u002Ffailed job — `replay_job` (MCP)\n- Send sidechannel message — `send_job_message` (MCP)\n- Get structured progress — `get_job_progress` (MCP)\n- Queue stats — `get_job_stats` (MCP; admin scope over HTTP, same as the other\n  jobs ops here — includes the wedged-queue silent-halt signal) or `gbrain jobs stats` (CLI)\n","# Minion Orchestrator\n\n## Contract\n\nMinions is a Postgres-native job queue for durable, observable background work.\nThis single skill handles two lanes:\n- Deterministic shell jobs (`gbrain jobs submit shell ...`)\n- LLM subagent jobs (`gbrain agent run ...`)\n\nWhen to route to Minions: durable, observable work that must survive restarts,\nfan out across many parallel tasks, or persist across sessions. Routing policy\nis defined in `skills\u002Fconventions\u002Fsubagent-routing.md` — the project default is\n`pain_triggered` (native subagents first, Minions after specific pain signals\nfire); Mode A (all-through-Minions) is opt-in.\n\nGuarantees:\n- Jobs survive gateway restart (Postgres-backed)\n- Every job has structured progress, token accounting, and session transcripts\n- Running agents can be steered mid-flight via inbox messages\n- Jobs can be paused, resumed, or cancelled at any time\n- Parent-child DAGs with configurable failure policies\n\nDurable-execution doctrine (routing convention the agent follows — nothing\nmechanically enforces it; see \"Durable execution\" below):\n- Operations expected to exceed ~2 minutes route through the capability\n  ladder, never a bare background shell that dies with the session.\n- A deadman check verifies the result was REPORTED to the user, not merely\n  that the process exited — a swallowed completion event looks identical to\n  a dead job from the user's side.\n- The deadman is second-line insurance, not a delivery guarantee: it can\n  itself die before firing (scheduler restart, deleted entry). Backstop:\n  on the next turn, sweep `gbrain jobs list --status active` and recent\n  completions for overdue work whose result never reached the user.\n- Deadman checks are idempotent. A double-fire, or a fire that races the\n  normal completion report, produces silence — it checks reported-state\n  first and tags any recovery report with the job ID so duplicates are\n  detectable.\n- A checkpoint or progress file is trusted only with a freshness check.\n  A stale checkpoint reads as \"still running\" forever; compare its\n  timestamp against the expected progress interval and against\n  `gbrain jobs get \u003Cid>`.\n\n## Route the Request: Shell Job vs Subagent\n\n| Condition | Action |\n|---|---|\n| User asks for deterministic command\u002Fscript run | Shell job (CLI: `gbrain jobs submit shell ...`) |\n| User asks to \"run in minions\" + explicit command\u002Fargv | Shell job (CLI, `--params` with `cmd` or `argv`) |\n| User asks for research\u002Freasoning\u002Fiterative agent | Subagent job (CLI: `gbrain agent run`) |\n| User asks to steer\u002Fpause\u002Fresume an agent | Subagent job lifecycle tools (MCP-callable) |\n| Single simple operation under ~30s | Consider inline execution first |\n| Needs restart durability\u002Fobservability | Submit as Minion job |\n| Operation expected to exceed ~2 minutes | Route through the Durable execution ladder (below) |\n| Parallel work (2+ streams) | `gbrain agent run --fanout-manifest` or parent + child subagents |\n\nIf intent is ambiguous, ask one clarification:\n\"Do you want a deterministic shell command job, or an LLM agent job?\"\n\n## Shell Jobs (Deterministic Scripts)\n\nUse for reproducible command execution, ETL steps, cron work, and scriptable\ntasks where no LLM reasoning loop is needed.\n\n### Preconditions (read before submitting your first shell job)\n\n- **The worker must be started with `gbrain jobs work --allow-shell-jobs`** (equivalently `GBRAIN_ALLOW_SHELL_JOBS=1` exported on the worker; a `.env` in the worker's directory cannot set it).\n  The shell handler is always registered but guarded: an unflagged worker that\n  claims a shell job dead-letters it immediately (`UnrecoverableError`, straight\n  to `dead`, no retries) with the flag named in `error_text`. A job that sits in\n  `waiting` means NO worker is running at all — check\n  `gbrain jobs supervisor status`. Gate lives in `src\u002Fcore\u002Fminions\u002Fhandlers\u002Fshell.ts`.\n- **Security:** flipping `GBRAIN_ALLOW_SHELL_JOBS=1` authorizes arbitrary\n  command execution on the worker. On a shared queue, this is a remote code\n  execution surface. Treat as privileged infrastructure authorization.\n- **Execution mode — pick one:**\n  - **Postgres + daemon:** `gbrain jobs work` runs a persistent worker that\n    claims and executes jobs from the queue.\n  - **PGLite + --follow:** `gbrain jobs submit ... --follow` runs inline.\n    The daemon mode is not available on PGLite (exclusive file lock). See\n    `docs\u002Fguides\u002Fminions-shell-jobs.md`.\n- **MCP boundary:** shell-job submission is CLI-only. `submit_job name=\"shell\"`\n  over MCP throws an `OperationError` with code `permission_denied`; generic\n  remote submission accepts only `sync`, `import`, `lint`, and `lint-fix`.\n  Agents CAN observe shell jobs via `get_job` \u002F `list_jobs` \u002F `get_job_progress`\n  (not protected), but cannot submit them. Operator or autopilot submits;\n  agent observes.\n- **Verify setup:** after configuration, run `gbrain jobs stats` (CLI) to\n  confirm the worker is registered and consuming the queue.\n\n### Submit (CLI, operator or autopilot)\n\nShell jobs take their command via `--params` as a JSON object with `cmd` (string)\nor `argv` (array), plus `cwd` and optional `env`.\n\nCommand string form:\n```\ngbrain jobs submit shell --params '{\"cmd\":\"echo hello\",\"cwd\":\"\u002Fabs\u002Fpath\"}'\n```\n\nArgv form (no shell expansion):\n```\ngbrain jobs submit shell --params '{\"argv\":[\"bash\",\"-lc\",\"echo hello\"],\"cwd\":\"\u002Fabs\u002Fpath\"}'\n```\n\nInline execution on PGLite or any one-shot deployment:\n```\ngbrain jobs submit shell --params '{\"cmd\":\"echo hello\",\"cwd\":\"\u002Ftmp\"}' --follow\n```\n\nQueue\u002Flifecycle flags exposed by `gbrain jobs submit --help`: `--queue`,\n`--priority`, `--delay`, `--max-attempts`, `--max-stalled`, `--backoff-type`,\n`--backoff-delay`, `--backoff-jitter`, `--timeout-ms`, `--idempotency-key`,\n`--dry-run`.\n\n### Monitor (agents or operator)\n\nThese operations are MCP-callable and safe for agent use:\n\n```\nlist_jobs --name shell --status active\nget_job ID\nget_job_progress ID\n```\n\nCheck structured result fields (exit code, stdout\u002Fstderr tails, attempts,\ntimings) from `get_job`. Use `get_job_stats` (MCP) or `gbrain jobs stats`\n(CLI) for the worker\u002Fqueue health dashboard incl. the wedged-queue signal.\n\n### Control (MCP-callable)\n\n```\ncancel_job id=ID\nreplay_job id=ID\n```\n\n`replay_job` is not protected — only shell *submission* is. Agents can\ncancel or replay a shell job without CLI access.\n\nUse idempotency keys for recurring shell workloads to avoid duplicate runs.\n\n## Subagent Jobs (LLM Orchestration)\n\nUse for open-ended reasoning, tool-using research, and fan-out synthesis.\n\n**User-facing entrypoint:** `gbrain agent run \u003Cprompt>` is the canonical way\nto submit subagent work. It handles the elevated-trust plumbing — `subagent`\nand `subagent_aggregator` are protected job names. Remote agents use the\ndedicated `submit_agent` operation with their configured source, tools, and\nslug binding; generic `submit_job` does not accept these job names.\n\n## Phase 1: Submit\n\n```\ngbrain agent run \"Research Acme Corp revenue\" --tools \"search,query\"\n```\n\n`--tools` accepts a comma-separated subset of `BRAIN_TOOL_ALLOWLIST` (see\n`src\u002Fcore\u002Fminions\u002Ftools\u002Fbrain-allowlist.ts`): `query`, `search`, `get_page`,\n`list_pages`, `get_backlinks`, `traverse_graph`, `list_link_sources`,\n`resolve_slugs`, `get_ingest_log`, `put_page`, `add_timeline_entry`,\n`get_recent_salience`, `find_anomalies`. Attachment tools and local-only\noperations are unavailable. Update old bindings before resubmitting jobs\nthat reference removed tools. Remote bindings must be nonempty; an explicit\nempty local tool list grants no tools.\n\nFor parallel work with a fan-out manifest:\n```\ngbrain agent run --fanout-manifest companies.json\n```\n\nThe manifest describes N children + 1 aggregator. Each child runs\n`name=\"subagent\"` under the hood; the aggregator runs `name=\"subagent_aggregator\"`\nand claims AFTER every child terminates. See\n`src\u002Fcore\u002Fminions\u002Fhandlers\u002Fsubagent.ts` and\n`src\u002Fcore\u002Fminions\u002Fhandlers\u002Fsubagent-aggregator.ts`.\n\nFlags (from `src\u002Fcommands\u002Fagent.ts`):\n- `--subagent-def \u003Cname>` — named subagent definition\n- `--model \u003Cid>` — override model\n- `--max-turns \u003CN>` — cap the LLM loop\n- `--tools \u003Ccsv>` — allow-listed brain tools (see above)\n- `--timeout-ms \u003CN>` — hard timeout per job\n- `--fanout-manifest \u003Cfile>` — N children + 1 aggregator\n- `--follow` \u002F `--no-follow` — stream logs + wait (default on TTY)\n- `--detach` — submit and return immediately\n\nQueue\u002Fpriority\u002Fretry tuning is not exposed by `gbrain agent run`; submit the\nraw `subagent` handler via `gbrain jobs submit` (requires CLI trust) if you\nneed those knobs.\n\n**Admission control (v0.46.11.0).** Identical parentless `subagent` submits\n(same owner lane, payload, and execution options) coalesce onto the existing\nwaiting job: `gbrain agent run` prints `coalesced` with the matched job id,\nand the `submit_agent` MCP response carries `coalesced: true`. Treat that as\nsuccess — monitor the matched id, do NOT resubmit. Jobs still waiting after\nthe TTL (48h default for `subagent`; `minions.ttl_waiting_hours.\u003Cname>`)\nare cancelled with reason prefix `waiting_ttl_expired`. If an operator has\nconfigured a waiting quota (`minions.quota_max_waiting.\u003Cname>`), a submit\npast the cap returns a structured, retryable `rate_limited` error — back\noff and check `gbrain jobs stats` for a `DIVERGENT QUEUE` line before\nretrying.\n\n## Phase 2: Monitor\n\n```\nlist_jobs --status active          # MCP — what's running?\nget_job ID                         # MCP — full details + logs + tokens\nget_job_progress ID                # MCP — structured progress snapshot\ngbrain jobs stats                  # CLI — queue health dashboard\ngbrain agent logs ID --follow      # CLI — streaming transcript + heartbeat\n```\n\nProgress includes: step count, total steps, message, token usage, last tool called.\n\n## Phase 3: Steer\n\nSend a message to redirect a running agent:\n```\nsend_job_message id=ID payload={\"directive\":\"focus on revenue, skip headcount\"}\n```\n\nThe agent handler reads inbox messages on each iteration and injects them as\ncontext. Messages are acknowledged (read receipts tracked).\n\nOnly the parent job or admin can send messages (sender validation).\n\n## Phase 4: Lifecycle\n\n```\npause_job id=ID                    # freeze without losing state\nresume_job id=ID                   # pick up where it left off\ncancel_job id=ID                   # hard stop\nreplay_job id=ID                   # re-run with same or modified params\nreplay_job id=ID data_overrides={\"depth\":\"deep\"}  # replay with changes\n```\n\nAll lifecycle ops are MCP-callable.\n\n## Phase 5: Review Results\n\n```\nget_job ID                         # result, token counts, transcript\n```\n\nToken accounting: every job tracks `tokens_input`, `tokens_output`, `tokens_cache_read`.\nChild tokens roll up to parent automatically on completion.\n\n## Durable execution (operations >2 minutes)\n\nBackground shells die silently: session compaction, harness restart, tool\ntimeout. Long gbrain operations (`extract all`, `embed --stale`, a full\n`sync --all`) routinely run 10-60 minutes — past every one of those\nceilings. And even when the work survives, the *completion event* can be\nswallowed (worker restart, dropped notification), leaving the user staring\nat silence while a finished result sits unreported. Durable execution\ncovers both halves: the work survives, and the report provably lands.\n\nRoute any operation expected to exceed ~2 minutes through the **highest\nrung of this ladder the deployment supports**. This is a harness-routing\nconvention the agent follows, not a mechanical guarantee — nothing stops a\nbare background shell except this skill saying don't.\n\n**Paid work gets consent before it is submitted.** A job runs without a\nterminal, so a paid command (`embed --stale`, or anything else that calls a\nmodel provider) stops with exit 3 and a consent payload unless it already\ncarries the user's approval. Get that approval first, in the conversation:\nrun the command's preview (for example `gbrain embed --stale --dry-run`),\nrelay the estimate, and only after the user agrees put the approval in the\nsubmitted command (`gbrain embed --stale --yes --max-usd \u003Ccap>` with the cap\nthey approved), or rely on a standing approval the user set with\n`gbrain config set consent.preapprove.paid.max_usd_per_run \u003Cusd>`. Never add\n`--yes` without the user's answer. When a job ends with exit 3 or the\n`confirmation_required` code, relay its message to the\nuser and stop; don't resubmit it with `--yes`.\n\n### Rung 1 — Minion job + deadman (Postgres + worker)\n\nRequires: Postgres engine, a running `gbrain jobs work` worker, and — for\nthe shell lane — a worker started with `--allow-shell-jobs` (or\n`GBRAIN_ALLOW_SHELL_JOBS=1` exported on it). All the\nPreconditions above still hold: the flag defaults OFF, shell submission is\nCLI-only across the MCP trust boundary, and PGLite has no worker daemon\n(see Rung 3). Nothing in this section loosens that contract.\n\n1. **Submit as a job** so the work survives restarts:\n\n   ```\n   gbrain jobs submit shell \\\n     --timeout-ms 3600000 \\\n     --params '{\"cmd\":\"gbrain extract all\",\"cwd\":\"\u002Fabs\u002Fpath\",\"inherit\":[\"database_url\"]}'\n   ```\n\n   Work that needs LLM judgment goes through the subagent lane\n   (`gbrain agent run`, above) instead — a submitted agent job you never\n   check on is the same bug as an unwatched shell job.\n\n2. **Arm a deadman in the same action block** (pattern below). Submitting\n   without arming is the classic half-fix: the job survives, the silence\n   doesn't.\n\n### Rung 2 — cron-checked progress file (no agent-waking scheduler)\n\nWhen no scheduler can wake the agent but the host has a plain crontab (or\nthe work runs outside the queue entirely): make the operation write a\nprogress\u002Fheartbeat file as it advances (or rely on `get_job_progress` for\nqueue jobs), and register a recurring host-cron check that compares the\nfile's freshness against the expected progress interval. The agent also\nchecks it at the start of the next turn. A checkpoint that stops advancing\nmeans **stalled**, not \"still running\" — the freshness comparison is the\nentire value of this rung.\n\n### Rung 3 — foreground + output buffering (PGLite \u002F no worker \u002F no scheduler)\n\nRun the operation inline in the foreground — on PGLite that's\n`gbrain jobs submit ... --follow`, or just the raw command — and buffer\nall output to a file, reading bounded slices, per\n`skills\u002Fconventions\u002Fexec-output.md`. An empty tool result after a long\ncommand is truncation, not a dead shell. This rung has no silent-death\ninsurance, so keep the operation in the foreground and stay with it;\nbackgrounding here recreates the exact failure the ladder exists to\nprevent.\n\n### The deadman pattern\n\nA one-shot, self-deleting scheduled check that fires at\nexpected-finish-plus-margin and verifies the **result was reported** — not\njust that the process exited. Arm it **in the same action block as the\nsubmission** (not after, not \"if I remember\").\n\n1. Estimate `expected_minutes` honestly; round up.\n2. Deadline = now + estimate + margin, where `margin = max(10 min, 50% of\n   estimate)`. Restarts delay delivery — too tight false-fires, hours-late\n   defeats the point.\n3. Create the check with whatever one-shot scheduler the host offers: a\n   harness cron tool with delete-after-run semantics, `at`, or a crontab\n   entry the check removes on first fire. The check's instruction:\n   - Verify the result was **already reported to the user**. `gbrain jobs\n     get \u003Cid>` gives the job state; the reported-check asks whether a\n     completion message actually reached the user.\n   - **Reported** → do nothing, stay silent, self-delete.\n   - **Completed but unreported** (swallowed event) → pull the result via\n     `gbrain jobs get \u003Cid>` and post the recovery report now, tagged with\n     the job ID.\n   - **Still running** → post a one-line status with a new ETA and arm ONE\n     follow-up deadman at +50% of the original estimate. One follow-up\n     max — no infinite chains.\n   - **Dead\u002Ffailed** → report what it produced before dying (`stderr_tail`\n     from `gbrain jobs get \u003Cid>`) and offer `gbrain jobs retry \u003Cid>`.\n4. **Disarm on normal completion.** When the completion arrives and you\n   report it, remove the deadman. If it fires anyway, the reported-check\n   makes it a silent no-op — belt and suspenders.\n\nFailure modes the pattern must own (mirrored in Contract and\nAnti-Patterns): the deadman itself dying before it fires (second-line\ninsurance, backstopped by the next-turn overdue sweep), double-fire\n(idempotent reported-check + job-ID-tagged reports), and stale checkpoints\n(freshness check before trusting \"still running\").\n\nEval contract, imported with the pattern — a deadman deployment is judged\non:\n\n- **ARMED_ON_SPAWN** — created in the same action block as the long\n  submission?\n- **SELF_DELETING** — one-shot, and silent when all is well?\n- **DETECTS_SWALLOWED** — verifies the result was reported, not just that\n  the job exited?\n- **RECOVERS** — on a swallowed event, pulls the output and posts the\n  recovery report?\n- **RIGHT_DEADLINE** — expected finish + sane margin, neither false-firing\n  nor hours late?\n\nHard fails: a long user-facing operation with no deadman armed; a deadman\nthat posts noise when the completion arrived normally; emulating the timer\nwith `sleep` or a poll loop instead of a scheduler entry (a sleeping\nprocess dies with the session — the exact failure being insured against).\n\n### Sequencing and locks\n\nMaintenance operations share locks (`sync`, `embed`, `extract`,\n`integrity`). Run them **sequentially, chained**: submit job 1, arm its\ndeadman; on completion, submit job 2, arm the next; finish with\n`gbrain doctor` and report the health delta. If a job dies mid-operation\nits lock expires at TTL (a live, recently-refreshed holder is protected by\nthe steal grace) — never hand-delete lock rows to \"unstick\" a queue.\n\n### Typical long operations\n\nDurations scale with corpus size; treat these as order-of-magnitude\nanchors for `--timeout-ms`, not promises.\n\n| Operation | Typical duration | Suggested `--timeout-ms` |\n|---|---|---|\n| `extract all` | 30-60 min on large brains | 3600000 |\n| `embed --stale` | 5-30 min (scales with missing count) | 1800000 |\n| `sync --all` | 5-20 min | 1200000 |\n| `integrity auto` | 10-30 min | 1800000 |\n| `dream` | 5-15 min | 900000 |\n\n### Appendix: content-addressed stage checkpoints\n\nFor a multi-stage pipeline with an expensive middle (extract → score →\nexplain → render → verify, where the scoring stage burns real LLM spend),\nmake each stage a content-addressed checkpoint so a crash — or a\ndeadman-triggered retry, or a `replay_job` — **resumes** instead of\nre-spending:\n\n- **Key each stage** on a hash of (the stage's own logic + its params +\n  the hashes of its upstream artifacts). Store artifacts under a `.cache\u002F`\n  directory in the pipeline's working tree, addressed by content hash.\n- **Warm re-run is a no-op**: every key matches, nothing recomputes, the\n  whole pipeline replays in well under a second.\n- **Busting cascades correctly**: a param change or a logic edit changes\n  that stage's key, recomputing it and every downstream stage whose\n  upstream hashes changed. The stage's own source must be part of the\n  key — omit it and logic edits silently reuse stale artifacts.\n- **Record provenance**: a provenance file per run records each stage's\n  key, inputs, outputs, and computed-at, so every artifact traces to the\n  exact logic + data that produced it and \"which stage recomputed and\n  why\" stays answerable.\n- **Verify integrity on restore**: check live artifacts against recorded\n  checksums; a mismatch means recompute or restore from cache, never\n  silent reuse.\n\nJudged on: **IDEMPOTENT** (warm re-run recomputes nothing),\n**CORRECT_BUSTING** (a change recomputes exactly the affected stages),\n**PROVENANCE** (every artifact traces to logic + params + upstreams),\n**INTEGRITY** (corrupted artifacts detected, never silently reused).\n\nThis composes with the ladder rather than replacing it: the ladder keeps\nthe pipeline running and reported; stage checkpoints keep a retry cheap.\nPair them whenever a single stage costs more than pocket change in LLM\nspend.\n\n## Output Format\n\nWhen reporting job status to the user:\n\n```\nJob #ID (name) — status\nProgress: step\u002Ftotal — last action\nTokens: input_count in \u002F output_count out (+ cache_read cached)\nRuntime: Xs\nChildren: N pending, M completed\n```\n\nWhen reporting completion:\n\n```\nJob #ID completed in Xs\nTokens used: input \u002F output \u002F cache_read\nResult: \u003Csummary>\n```\n\nWhen reporting batch status (parent with children):\n\n```\nParent #ID — waiting-children\n  #A subagent(Acme) — active, 3\u002F5 steps, 2.5k tokens\n  #B subagent(Beta) — completed, 1.8k tokens\n  #C subagent(Gamma) — paused\nTotal tokens so far: 4.3k\n```\n\n## When it fails\n\nFollow the [agent operator protocol](..\u002Fconventions\u002Fagent-operator-protocol.md) for any gbrain error `code`, exit code, `[AGENT]` block or notice block. Specific to this skill:\n\n- `gbrain jobs submit` over MCP for a protected job returns `permission_denied`: it must run from the trusted local CLI on the brain host; tell the user.\n- A shell job dead-letters immediately with the flag named in `error_text` (shell jobs disabled): tell the user which env flag the host operator must set; do not retry.\n- `rate_limited` from the submission cap: back off for the stated delay before resubmitting; do not fan out more submissions meanwhile.\n- A job sits in `waiting` with no worker: confirm a worker is registered (`gbrain jobs get \u003Cid>`) before resubmitting.\n\n## Anti-Patterns\n\n- Don't spawn a Minion for a single search query (use search tool directly)\n- Don't fire-and-forget without checking results\n- Don't spawn > 5 concurrent agents without checking `gbrain jobs stats` first\n- Don't resubmit when a submit reports `coalesced` — the work is already queued; monitor the matched job id instead\n- For subagent work, don't use `sessions_spawn` with `runtime: \"subagent\"` when Minions is available (use `gbrain agent run` instead)\n- Don't poll `get_job` in a tight loop (use `get_job_progress` for lightweight checks)\n- Don't run an operation expected to exceed ~2 minutes as a bare background shell — it dies with the session; route through the Durable execution ladder\n- Don't say \"I'll report back when it finishes\" without an armed deadman or a scheduled check that will actually fire\n- Don't let a deadman post noise when the completion arrived normally — check reported-state first, stay silent, self-delete\n- Don't emulate the deadman timer with `sleep` or a poll loop — a sleeping process dies with the session, which is the exact failure being insured against\n- Don't trust a checkpoint or progress file without a freshness check — a stale checkpoint reads as \"still running\" forever\n- Don't run lock-acquiring maintenance ops (`sync`, `embed`, `extract`, `integrity`) simultaneously, and don't hand-delete lock rows to unstick them (locks expire at TTL)\n\n## Tools Used\n\n- Submit a background job — `submit_job` (MCP: only `sync`, `import`, `lint`, and `lint-fix`, under the contract in `docs\u002Fguides\u002Fauthorization-upgrade.md`; shell jobs use the local CLI, remote subagents use `submit_agent`)\n- Get job details — `get_job` (MCP)\n- List jobs with filters — `list_jobs` (MCP)\n- Cancel a job — `cancel_job` (MCP)\n- Pause a job — `pause_job` (MCP)\n- Resume a paused job — `resume_job` (MCP)\n- Replay a completed\u002Ffailed job — `replay_job` (MCP)\n- Send sidechannel message — `send_job_message` (MCP)\n- Get structured progress — `get_job_progress` (MCP)\n- Queue stats — `get_job_stats` (MCP; admin scope over HTTP, same as the other\n  jobs ops here — includes the wedged-queue silent-halt signal) or `gbrain jobs stats` (CLI)\n",{"name":5,"tools":61,"version":71,"mutating":72,"triggers":73,"upstream":100,"description":101,"when_to_use":102},[62,63,64,65,66,67,68,69,70],"submit_job","get_job","list_jobs","cancel_job","pause_job","resume_job","replay_job","send_job_message","get_job_progress","1.1.0",true,[74,75,76,77,78,79,33,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99],"gbrain jobs submit","submit a gbrain job","submit a shell job","shell job","run shell command in background","deterministic background task","background task","run in background","check on agent","agent progress","what's running","steer agent","change direction","tell the agent","pause agent","stop agent","resume agent","parallel tasks","fan out","do these in parallel","long operation","durable execution","arm a deadman","the job went silent","operation died in the background","make this pipeline resumable","long-ops@fc834ee, subagent-deadman@fc834ee, pipeline-stage-cache@fc834ee","Unified Minions skill for both deterministic shell jobs and LLM subagent\norchestration. Replaces the older `gbrain-jobs` routing intent. Use when:\nsubmitting gbrain jobs, shell\u002Fbackground tasks, spawning subagents,\nchecking progress, steering running work, pausing\u002Fresuming, parallel\nfan-out. One durable, observable, steerable queue interface. Also carries\nthe durable-execution doctrine for any operation expected to exceed ~2\nminutes: capability ladder, deadman checks that verify the result was\nreported, and content-addressed stage checkpoints for expensive pipelines.\n","Use when the user asks: \"gbrain jobs submit\", \"submit a gbrain job\", \"submit a shell job\", \"shell job\", \"run shell command in background\".","master","074ec301549ded4930f04d2c3b22d709a6c095cc","plugin\u002Fskills\u002Fminion-orchestrator",4884,"https:\u002F\u002Fgithub.com\u002Fgarrytan\u002Fgbrain","https:\u002F\u002Fgithub.com\u002Fgarrytan","https:\u002F\u002Fblog.garrytan.com","Writes software, dreams. ","2026-11-13 04:05:07",{"source":8,"skillName":5,"commands":113,"prompt":123,"zipAvailable":72},[114,117,120],{"tool":115,"command":116},"npx","npx skills add garrytan\u002Fgbrain --skill minion-orchestrator",{"tool":118,"command":119},"bunx","bunx skills add garrytan\u002Fgbrain --skill minion-orchestrator",{"tool":121,"command":122},"pnpm","pnpm dlx skills add garrytan\u002Fgbrain --skill minion-orchestrator","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fgarrytan\u002Fgbrain\u002Fblob\u002Fmaster\u002Fplugin\u002Fskills\u002Fminion-orchestrator\u002FSKILL.md",[125],{"path":126,"resourceType":127,"resourceTypeDesc":128,"sizeBytes":129,"sourceHtmlUrl":130},"routing-eval.jsonl","OTHER","其他",1229,"https:\u002F\u002Fgithub.com\u002Fgarrytan\u002Fgbrain\u002Fblob\u002Fmaster\u002Fplugin\u002Fskills\u002Fminion-orchestrator\u002Frouting-eval.jsonl",[132,145,151,174,200,214],{"skillNo":133,"name":134,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":135,"categories":136,"keywords":137,"publishedAt":56},"01M6N109FNGH1PK49T734PZXGB","query-helper","https:\u002F\u002Fgithub.com\u002Fgarrytan\u002Fgbrain\u002Fblob\u002Fmaster\u002Ftest\u002Ffixtures\u002Fskill-catalog\u002Fskills\u002Fquery-helper\u002FSKILL.md",[],[138,139,140,141,142,143,144],"query helper","helper","query","search","page","find","false",{"skillNo":146,"name":147,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":148,"categories":149,"keywords":150,"publishedAt":56},"01M6N108A23GW6NGQEQ0E7GV0A","broken","https:\u002F\u002Fgithub.com\u002Fgarrytan\u002Fgbrain\u002Fblob\u002Fmaster\u002Ftest\u002Ffixtures\u002Fskill-catalog\u002Fskills\u002Fbroken\u002FSKILL.md",[],[147],{"skillNo":152,"name":153,"nameZh":6,"description":154,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":155,"categories":156,"keywords":157,"publishedAt":56},"01M6N105E88C5K2H03H0CC79G1","brain-ops","Read, enrich, and write brain pages with source attribution.","https:\u002F\u002Fgithub.com\u002Fgarrytan\u002Fgbrain\u002Fblob\u002Fmaster\u002Ftest\u002Ffixtures\u002Fskill-catalog\u002Fskills\u002Fbrain-ops\u002FSKILL.md",[],[158,159,160,161,162,142,163,164,165,166,140,167,168,169,170,171,172,173,141],"brain ops","brain","ops","true","attribution","read","write","up","look","pages","people","with","enrich","web","path","source",{"skillNo":175,"name":176,"nameZh":6,"description":177,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":178,"categories":179,"keywords":185,"publishedAt":56},"01M6N102GRMF22TVCNT6RK5MRD","meeting-prep","Build a briefing before you meet someone, from their recent threads, open loops and what they care about.","https:\u002F\u002Fgithub.com\u002Fgarrytan\u002Fgbrain\u002Fblob\u002Fmaster\u002Ftest\u002Ffixtures\u002Fskill-catalog-query\u002Fskills\u002Fmeeting-prep\u002FSKILL.md",[180],{"categoryNo":181,"categoryName":182,"taxonomyType":183,"taxonomyTypeDesc":184},"01JBSEEDCAT000000000000034","行政与办公人员","PROFESSION","适用职业",[186,187,188,189,190,141,191,192,193,140,144,194,195,196,197,198,35,199],"meeting","prep","meeting prep","me","prepare","brief","open","build","loops","about","you","briefing","threads","Meet",{"skillNo":201,"name":202,"nameZh":6,"description":203,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":204,"categories":205,"keywords":206,"publishedAt":56},"01M6N1005QK7REHX5KGMNR5PF0","inbox-zero","Triage the inbox into replies, delegations and archives.","https:\u002F\u002Fgithub.com\u002Fgarrytan\u002Fgbrain\u002Fblob\u002Fmaster\u002Ftest\u002Ffixtures\u002Fskill-catalog-query\u002Fskills\u002Finbox-zero\u002FSKILL.md",[],[207,208,209,141,210,144,211,212,213],"inbox zero","ZeRO","inbox","clear","replies","my","triage",{"skillNo":215,"name":216,"nameZh":6,"description":217,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":218,"categories":219,"keywords":220,"publishedAt":56},"01M6N0ZXQ8RRRW71PNV61T57GP","deal-memo","Draft an investment memo from the deal pages and the founder history already in the brain.","https:\u002F\u002Fgithub.com\u002Fgarrytan\u002Fgbrain\u002Fblob\u002Fmaster\u002Ftest\u002Ffixtures\u002Fskill-catalog-query\u002Fskills\u002Fdeal-memo\u002FSKILL.md",[],[221,222,223,167,159,224,225,164,226,161,141,227],"deal memo","deal","memo","draft","investment","history","founder"]