Use when the user's cwd contains .orchestrator/ or tasks.json (a project managed by the orch CLI). Explains the task DAG model, where runtime state lives (SQLite), how to inspect it without editing tasks.json, how to legally move a task between states, and which commands are safe from an agent session. Load on demand — no need to keep in system prompt.
Scanned 9/23/2026
Install to Claude Code
npx -y skills add hectorcanaimero/orch --skill orch --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Orch?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/hectorcanaimero-orch)More formats (shields.io, HTML) on the badges page.
---
name: orch
description: Use when the user's cwd contains .orchestrator/ or tasks.json (a project managed by the orch CLI). Explains the task DAG model, where runtime state lives (SQLite), how to inspect it without editing tasks.json, how to legally move a task between states, and which commands are safe from an agent session. Load on demand — no need to keep in system prompt.
---
# Orch — task orchestrator operating manual
`orch` is a local CLI that walks a `tasks.json` DAG and dispatches each task
to Claude / Codex / OpenCode / Gemini in parallel, opens a PR per task, polls
CI, and shows the whole thing on a stakeholder dashboard.
**Getting `orch` on this machine:** it is a single static binary (Linux and
macOS, `amd64`/`arm64`). Check `orch --version` first; if it is missing, ask
the user before installing anything, then use one of:
```bash
curl -fsSL https://raw.githubusercontent.com/hectorcanaimero/orch/main/scripts/install.sh | sh
brew install hectorcanaimero/orch/orch
```
The script verifies the release checksum and installs to `~/.local/bin`
(`INSTALL_DIR=...` to override). A tarball from the Releases page works too.
The old Python package (`pipx`, `v0.11.0-py`) is frozen; both read the same
`tasks.json` and `config.yaml`. Repo: <https://github.com/hectorcanaimero/orch>.
**The skills themselves:** `orch install-skills --all` installs this skill and
the planning pipeline below into Claude Code (`~/.claude/skills/`); add
`--target codex`, `--target opencode` (a section in the project's `AGENTS.md`)
or `--target cursor` (`.cursor/rules/`) for other agents.
---
## What this project looks like
Every orch-managed project has:
- `tasks.json` — the DAG (task ids, deps, model assignment, files, spec_ref).
**Static input, not the source of runtime status.**
- `.orchestrator/config.yaml` — single config file (concurrency, budget,
dispatch, github, notifications, dashboard, presentation).
- `.orchestrator/model_router.yaml` — `{tasks.json model string → CLI
invocation}`. Stub by default; populated by `orch router add-missing`.
- `.orchestrator/state/<project_id>/orch.db` — **SQLite runtime store**.
This is the single source of truth for task status once dispatch has
started. Tables: `projects`, `tasks_definition`, `tasks_runtime`,
`runs`, `dispatches`, `events`, `spend`, `milestones`.
- `scripts/task-{start,finish,block}.sh` — the shell-out protocol a
dispatched agent runs to signal state transitions, when it has no MCP
tools.
- `.mcp.json` — points an MCP-capable agent at `orch mcp`, which serves the
same transitions as tools (and five read-only ones the scripts have no
equivalent for). Written by `orch init` since G6.4.
- `.github/workflows/orch-ci.yml` — CI hook auto-generated by `orch init`
(skipped when a workflow already exists).
A project still on the legacy file backend (`state.backend: file` in
`config.yaml`, or a `.orchestrator/state/events-*.jsonl` with no `orch.db`
next to it) has no runtime database yet — run `orch migrate` once before
anything below about reading or transitioning state applies.
## Hard rules — read these before touching anything
1. **Never edit `tasks.json` status in place.** Runtime status lives in
`tasks_runtime`. Use `orch task set --id ID --status STATUS` or one of
the `scripts/task-*.sh` helpers. Direct edits are silently discarded.
2. **Never run `git worktree add -b orch/...` by hand** inside a project
with `dispatch.worktree_mode: true`. `orch run` owns those
branches — a manual create leaves an orphan branch that blocks the
next dispatch.
3. **Never bypass `orch task set` transitions.** Legal transitions are
enforced by SQLite; forcing a state via `sqlite3` CLI can leave the
dashboard, dispatcher, and `orch status` reporting different values.
4. **Model names in `tasks.json` are contract.** They resolve through
`model_router.yaml`. If the router doesn't have an entry for a model
the task references, `orch validate` fails loudly — run
`orch router add-missing --yes` before re-dispatching.
## How to read state (safe from any agent session — read-only)
```bash
orch status # human table
orch tasks --status todo,in-progress # narrower view
orch events <TASK_ID> # tail events for one task
orch logs <TASK_ID> # tail the task's log
orch graph # emit the DAG (DOT)
orch doctor # read-only environment preflight
orch validate # static graph validation
```
Direct SQL lookup when you need it (still read-only):
```bash
sqlite3 .orchestrator/state/<project_id>/orch.db \
"SELECT task_id, status, last_model FROM tasks_runtime
WHERE status != 'done' ORDER BY task_id;"
```
## Reporting back from a dispatched task
If you were launched by `orch run`, your prompt names two channels and you use
**one**:
```
orch_set_status task_id "F1.T2", status "done", note "<what you did>", author "<your model>"
orch_block task_id "F1.T2", reason "<why>", author "<your model>"
```
or, with no MCP tools:
```bash
scripts/task-finish.sh F1.T2 "<what you did>" "<your model>"
scripts/task-block.sh F1.T2 "<why>" "<your model>"
```
Three things about that note, all of which cost real work when missed:
- **It is the next task's context.** Every task that depends on yours gets it
rendered in its own prompt under `Completed dependencies (context):`. A note
reading "done" tells the next agent nothing.
- **Pass an author.** It is how orch tells a report from its own bookkeeping —
the engine writes `dispatched to …` and `dispatch succeeded` under the author
`orch`, and a note attributed to `orch` is read as bookkeeping and never
shown downstream.
- **The task is already `in-progress`.** The orchestrator moved it before
launching you. Never run `scripts/task-start.sh` yourself.
The other five tools are read-only: `orch_list_tasks` (with `ready: true` for
what could be dispatched now), `orch_get_task`, `orch_context` (your task plus
what its dependencies reported), `orch_events`, `orch_budget`. See
`docs/MCP.md` in the orch repo.
## Reporting a problem with orch itself
When **orch** (not the project) gets in your way — a wrong status, a refused
tool, a message that misled you — or you notice what it should do better or
does not do at all — a command or flag you looked for, a step you had to do by
hand that orch could do — report it with
`orch_report_finding` (`type` bug|improvement|feature, `title`, `summary`,
optional `evidence`, `repro`, `suggested_fix`, `confidence`). It files an
`auto-reported` issue on hectorcanaimero/orch, so keep it about orch: no
secrets, no project code or names. It searches first and returns an existing
report instead of filing a duplicate; if it lists similar issues, read them
and call again with `confirm_new: true` only if yours is different. It works
only when the project sets `report_findings.enabled: true` (what `orch init`
writes; a config without the key is off); when off, tell the operator instead. Then carry on with your task.
## How to transition a task
A task's status only ever moves along one legal path:
`backlog → todo → in-progress → done | blocked`, with `blocked → todo` to
recover and `done → todo` as the only reopen. `orch task set` and
`orch task-status` both enforce this — an illegal move (e.g. `done` straight
to `in-progress`) is rejected, never silently coerced.
```bash
orch task set --id F1.T2 --status done
orch task-status F1.T2 in-progress --author me --note "picking this up"
orch reset # revert stuck in-progress → todo (dry-run first)
```
`orch reset` is dry-run by default — it prints what it would revert. Pass
`--requeue` to actually apply it.
`orch task set` only changes status in this binary: its `--model` and
`--backend` flags exist but refuse to run. There is no milestone to assign: a
milestone is a phase. To change a
task's model, edit `Model` in its spec and re-run `orch atomize` (see
`orch-tasks`). A running `orch run` stops on Ctrl+C (SIGINT) or SIGTERM: it
dispatches nothing new, waits for what is in flight and exits 130; a second
signal kills the in-flight agents.
## Migrating an old file-backend project
A project that predates the SQLite backend (or was scaffolded with
`state.backend: file`) needs a one-time import before `status`/`tasks`/
`task set` mean anything:
```bash
orch migrate --dry-run # see what would be imported, touches nothing
orch migrate # import + backs up the old state dir first
```
`orch migrate` is deprecated the day it ships — it exists only to carry
history forward once, not as a command you run repeatedly.
## When the user asks about the dashboard / stakeholder view
```bash
orch dashboard # local read-only server
orch dashboard --profile stakeholder # curated client view
orch dashboard --tunnel # Cloudflare quick tunnel; prints token links
orch notify test # verify Slack/Discord webhook
orch notify digest # print stakeholder digest (cron this)
```
## Provider concurrency + budget
- Concurrency caps live in `config.yaml → concurrency.per_provider`.
- Budget guardrails: per-provider token windows in `.orchestrator/budgets.yaml`
(preset chosen by `budgets_preset` in config.yaml), plus
`budget.per_dispatch_usd` as claude's per-attempt `--max-budget-usd`. No
project-wide USD limit. A task waiting on a capped provider shows
`defer_reason: blocked-by-budget:…` in `orch status --json`.
- Silent-fail on Slack/Discord: a broken webhook must never take down
the dispatch loop.
## DAG resolution — how tasks become "ready"
A task is `ready` when:
- Its own status is `todo`.
- Every dep listed in `tasks.json` is `done` in `tasks_runtime`.
- It matches the `--only` glob (if the operator passed one).
Dependencies of blocked tasks do NOT unblock — a blocked task stops its
subtree until an operator resets it.
## Planning new work — the pipeline skills
New work reaches `tasks.json` through four documents, each with its own skill:
| Skill | Writes | From |
| --- | --- | --- |
| `orch-prd` | `docs/prd/NNN-<slug>.md` | an idea |
| `orch-arch` | `docs/arch/NNN-<slug>.md` | the PRD and the code |
| `orch-spec` | `specs/f<N>-<slug>.md` | the architecture |
| `orch-tasks` | `tasks.json`, via `orch atomize --apply` | the specs |
`orch-plan` runs all four with a stop for the user after each document and
before anything is applied. Never write tasks into `tasks.json` by hand when
a spec exists for them: the next `orch atomize` would report them as orphans.
## Where to find more
- `orch --help` and `orch <verb> --help` — the source of truth for flags.
- `docs/MANUAL.en.md` / `docs/MANUAL.es.md` in the orch repo — deep dives.
- `docs/CLI.md` — what the Go rewrite of the CLI implements today, if
you're on that binary.
- `docs/MCP.md` — the `orch_*` tools and how `.mcp.json` wires them.
- `docs/DELIVERING-TO-STAKEHOLDERS.md` — how to hand the URL to a client.
- `docs/brainstorm/next-sprints.md` — living roadmap.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!