# AUTOPILOT-32 — the package owns `/orchestrate`

Before this change the orchestrator procedure existed as five copies kept in
step by a shell script, a dotfiles pre-commit hook, and a drift gate: a
canonical body at `~/.config/agents/commands/orchestrate.md`, projections for
pi (`.pi/personal/prompts/`), opencode (`.config/opencode/{work,personal}/
command/`) and Claude Code (`.claude/commands/`), plus a verbatim copy pushed
into this repo's `prompts/orchestrate.md`. Nothing loaded the packaged file at
runtime — the hosts read their own projection.

All of that machinery existed only because no host registered the command from
the package. Both hosts this package loads into can:

- **pi** — `pi.registerCommand("orchestrate", …)` (`src/hosts/pi-extension.ts`).
- **opencode TUI** — `api.keymap.registerLayer({ commands: [{ …, slashName:
  "orchestrate", run }] })`, with `TuiPromptRef.set()` + `submit()` placing the
  procedure into the session (`src/hosts/opencode-tui.ts`). The opencode
  *server* plugin genuinely cannot: its hooks only expose
  `command.execute.before` observers.

Both serve `prompts/orchestrate.md` from the package at runtime
(`orchestrateProcedure()` in `src/framework/orchestrate-command.ts`).

## The two halves must land together

The dotfiles half — deleting the pi/opencode projections, declaring `stateDir`
in `autopilot.host.json`, and removing the cross-repo sync — lives on the
dotfiles branch `autopilot-32-dotfiles-retire`. Merging it BEFORE this repo's
command registration lands leaves the machine with no `/orchestrate` at all:
the projections are gone and nothing has replaced them. Merge both, or
neither.

## Precedence is empirical, and it differs per host

Measured 2026-09-10 by registering the plugin command while a same-named file
existed and observing which one ran — not inferred from docs.

| host | winner when both exist |
| --- | --- |
| pi | the **extension command**. `pi --mode rpc` + `/orchestrate` ran the extension handler; `get_commands` lists both under the plain name, so the list alone does not reveal the winner. |
| opencode | the **command FILE**. Driving the real TUI through a pty, the palette showed both and `/orchestrate` rendered the file's body — `run()` never fired. |

So on opencode a stale projection *silently shadows* the packaged procedure.
That is why the conflict report (D4) names every competing path **and** which
one actually wins, once per session.

## The per-profile fact moved out of the prompt

`- STATE_DIR: <path>` used to live inside each projected command file — the one
per-profile fact, and the reason the procedure had to be copied per profile at
all. It now lives in `autopilot.host.json` in the host's own config dir
(`$PI_CODING_AGENT_DIR` / `$OPENCODE_CONFIG_DIR`):

```json
{ "stateDir": "~/.local/state/orchestrator/work" }
```

The migration is outright: nothing reads the command file any more.
`resolveStateDir()` is `AUTOPILOT_STATE_DIR` → that file → profile fallback, and
the AUTOPILOT-3 probe reports which of the three answered.

## The sync must never write another repo

The retired package-prompt entry ran `cp <canonical> ~/personal/
orchestrator-autopilot/prompts/orchestrate.md` from a dotfiles **pre-commit
hook**. On 2026-09-10 it silently staged 18 insertions and 95 deletions into
this repo while three workers had unmerged edits open here. The entry is gone;
the surviving marker sync now refuses loudly (`write_allowed()` in
`scripts/sync-agent-prompts.sh`) on a target outside the dotfiles repo or with
uncommitted changes, and a refusal fails the run in write mode as well as
`--check`.

## Open question: Claude Code

Claude Code loads neither a pi extension nor an opencode plugin, so the package
cannot serve `/orchestrate` there. `~/.claude/commands/orchestrate.md` and the
canonical body it projects from are therefore **retained pending the user's
answer** to "do you orchestrate from Claude Code?". Both are reported by the
conflict warning as present but "not loaded by this host".

Remaining work once answered:

- **(a) yes, keep it** — re-point the `<!-- canonical-command: … -->` marker in
  `.claude/commands/orchestrate.md` at this repo's `prompts/orchestrate.md`,
  delete `~/.config/agents/commands/orchestrate.md`, and comment the sync entry
  as the one host the plugin cannot reach. One line of source, one deletion.
- **(b) no, drop it** — delete `.claude/commands/orchestrate.md` and
  `~/.config/agents/commands/orchestrate.md`; no sync survives for this command,
  and the `.claude/commands` entry in `PER_TOOL_DIRS` needs no change (it is
  generic).

Either way the canonical copy cannot be deleted *before* the answer: while the
`.claude` projection still carries its marker, removing the source makes
`sync-agent-prompts.sh --check` fail every dotfiles commit.
