The orchestrator was running `git add ./TODO/` and `git commit -m
chore(todo): ...` itself in Phase 9, baking filesystem-tracker
specifics into commands/workflow.md. The point of @pm as an
abstraction is that it should be swappable — a Linear-backed @pm or a
Notion-backed @pm should drop in without touching the workflow
command. With API-backed trackers, "commit the TODO updates" is a
no-op and `git add ./TODO/` is wrong.
Push persistence shape behind the @pm boundary:
- New @pm capability `Commit pending changes` accepts a commit message
and returns {ok, sha, message}. Filesystem @pm runs `git add ./TODO/`
+ `git commit -m <msg>` and returns the SHA. Tracker-backed
implementations no-op and return sha: null.
- @pm gains tightly-scoped bash access: `git add ./TODO/*`,
`git commit -m *`, `git status --porcelain ./TODO/*` only. Push,
reset, rebase, checkout, branch, tag are explicit denies. Everything
else falls through to the default deny.
- Phase 9 "Commit TODO Changes" replaces orchestrator-side git with a
@pm dispatch; orchestrator constructs the message from run context
and captures the returned SHA for the summary.
- Failure Handler gains a step 5 (commit pending after the failure
comment add). Today the comment is left uncommitted in the working
tree and gets discarded with the throwaway worktree (ADR-14) —
forensic loss. With this change the failure note lands as its own
commit on the failed branch.
- Routing matrix Phase 9 rows updated; ADR-22's superseded wording
about orchestrator-side staging removed.
Stub-pass / body-pass / wip code commits remain orchestrator-owned —
those are code, not tracker-specific.
Refs: config/opencode/workflow-design.md ADR-23