Ticket
One ticket, one verb at a time. Each verb is a full procedure in verbs/<verb>.md;
read that file before doing anything else, then follow it. This page holds only
what every verb shares.
Invocation
/ticket <verb> <ticket-id>, where verb is triage, start, revise, or
finalize. No verb or no ticket id: ask for it, one line. Unknown verb: list the
four.
The pipeline
triage reads the ticket and the repo, interviews the user through /scope
when scope is thin, and ends by posting the work order: a locked brief as a
ticket comment. Work too big for one agent's context is sliced into sub-orders
in that same comment (references/slicing.md). It
writes nothing to the repo except scope and spec documents committed in the
ticket's worktree. An epic child treats its issue-body order as a draft and may
commit a required parent-plan amendment in the child worktree before posting the
reviewed lock; that amendment travels with the implementation pull request.
start runs in a fresh session, fetches the work order, refuses if there is
none, implements it on a branch in an isolated worktree (or, on a sliced order,
coordinates one agent per chunk), iterates the verification step until the
result matches the order's expectation, passes an adversarial review at the
order's stamped depth (references/review-depth.md)
unless Profile: hardening replaces it below Full depth,
opens the pull request, and stops. Agents never merge.
revise actions one review round on the open pull request: reload the ticket
and the order, fix, re-verify, push.
finalize runs after a human merged: verify the merge and post-merge workflow,
complete the repository's post-merge archive guidance for an ordinary OpenSpec
change, which opens a reviewed archive pull request and posts its Archive PR:
locator before stopping, then on a later finalization, once a human merged that
pull request, close the ticket with a comment linking the pull request, record
what the ticket actually cost in context, and tear the worktree down, so this
repo's slicing calibration is tuned against measured numbers rather than
intuition.
The tracker contract
Every tracker interaction goes through four operations: read a ticket, post a
comment on a ticket, move a ticket's status, and locate the newest work order on
a ticket. references/tracker-contract.md
defines them, and one binding page supplies them for one tracker. GitHub issues
ship as the reference binding
(bindings/github-issues.md).
The procedures below and in verbs/ call the contract, never a tracker's API
directly. A verb that cannot reach the contract stops and names what is missing.
Review front door
start and revise reach code review as /review on the changed code, which
routes to code-review. Neither verb calls a reviewer any other way, and neither
substitutes a lighter check for the depth the order stamped. Below Full depth under
Profile: hardening, start and revise use its
exception instead.
Delegation authority
This authority covers triage's mandatory /plan-review and start/revise's /review route. Invoking /ticket authorizes every sub-agent dispatch that this procedure marks mandatory, including the coordinator's mandatory reviewer dispatch. Do not ask again solely because a session-level preference says "do not spawn agents"; apply that preference to discretionary delegation only. An explicit task-level refusal of this required review or revocation of delegation overrides this authorization: stop and state that the requested workflow cannot run without its required independent review.
When Ticket work is delegated, the delegation prompt identifies the
mandatory-review handoff. At that boundary the worker returns or writes its
review-ready result through the coordinator-recorded durable result locator and
does not launch a reviewer. The coordinator dispatches every mandatory reviewer
through the existing adapter after collecting the result, verifies the returned
verdict, and resumes the same worker. Actionable findings resume it for correction; a
verified clean verdict resumes it to finish. A failed launch, nonzero exit,
missing result artifact, or missing verdict is reported as unavailable and blocks
the workflow from advancing as reviewed. Direct nested adapter dispatch by the
worker is unsupported.
Selected-ticket mutation boundary
Triage may mutate operator-local workflow state required by the installed workflow
to execute the selected ticket lifecycle. Current examples include the lifecycle
claim, exact-worktree Codebase Memory state, reviewer-memory store, and local
remote-tracking refs used to resolve and verify the selected ticket's base. These
examples make the purpose concrete; they are not an exhaustive list.
Triage may also mutate repository or tracker state belonging to the selected ticket
lifecycle without ancillary approval. Current examples include the selected worktree
and branch, an ordinary ticket's active change, the selected ticket's comment and
status, and the defined Epic-child parent-plan amendment carried by that child's
implementation pull request. These examples make the ownership concrete; they are
not an exhaustive list.
This authority does not authorize state for a distinct external concern:
independently addressable work outside the selected lifecycle, such as another
branch, pull request, issue, ticket, or repository artifact outside the selected
branch. Broad read-only grounding never authorizes it.
Shared rules (every verb)
Open with the ticket summary. Before any other work, read the ticket and
give the user an extremely high-level, human-readable summary: what the ticket
is and what this verb is about to do on it (as simple as "implementing
<ticket-id>, which is <one-line description>"). Then mark a chapter titled
<ticket-id> <verb> when the harness offers a chapter tool, so the user can
scroll back to it. Skip the chapter silently when it does not.
Claim the session. Immediately after the ticket summary, run
python3 <ticket-skill-directory>/scripts/ticket.py claim <ticket-id> --verb <current verb>, so the
sessions that worked this ticket are recorded as they work it rather than
guessed from prose afterwards. Pass --session and --agent whenever the
environment cannot answer on its own: no session id in it, or more than one,
which is what a worker launched from another agent's session sees. Pass
--role to say what the session is doing on the ticket: coordinator (the
session driving the ticket, and the default), worker (an agent building one
chunk), or reviewer (a session that only reviews). The role decides which
costs are evidence about how big the work was, so a session claimed under the
wrong one is a measurement error. The required --verb is triage, start,
revise, or finalize, matching the lifecycle verb this session is running.
One session serves one lifecycle verb: same-verb resumes reuse the claim, while
changing verbs requires a fresh session. A cross-verb re-claim keeps and prints
the persisted claim, reports the persisted and submitted verbs as one visible
conflict, and exits successfully; telemetry never claims the submitted metadata
landed. A claim that fails is said in one
line and never blocks the verb: telemetry is a measurement, not a gate. A
sandboxed session (a Codex workspace-write sandbox, for one) that cannot
write the claims file under ~/.config/ticket/ sees that one-line denial
name the path and the fix: rerun the same claim command outside the sandbox
or with escalated permissions.
Attribution first. Every comment this skill posts opens with a one-line
quote block. With an operator name configured:
Written by an AI agent operating for <operator>. Verify before relying on it.
With none configured:
Written by an AI agent. Verify before relying on it.
The name comes from ~/.config/ticket/config.json, key operator. No file, no
key, or an empty value all mean the nameless form. Then the content. Never post
an unattributed comment.
The lock is the only entry to execution. A work order is a ticket comment
whose fence header starts EXECUTION LOCK (any version) or, on a ticket still
running the legacy protocol, WORK ORDER. start and revise locate it with
the tracker contract's locate operation
(references/tracker-contract.md): newest
comment wins by post time across both protocols, and no field is ever merged
from an older comment into a newer one. No order, no execution: refuse and
route to /ticket triage <ticket-id>. Admission is the consumer's job: an
unrecognized EXECUTION LOCK version or Source: mode refuses the same way
rather than falling back to an older comment. A legacy WORK ORDER keeps
today's sufficiency rules with no inferred pin, forever; any supersession uses
the new protocol.
One worktree, one branch, per ticket, for the whole lifecycle. triage
cuts the branch and worktree through spin-worktree; start and revise
reuse them; finalize tears them down. The first repository action after the
summary-and-claim opening, before grounding or any repo read, is to cut or
reuse the ticket's worktree. The one pre-worktree exception is fresh epic-child
triage: it fetches and verifies the issue body's pinned remote parent-plan base,
then passes that branch to the helper. Outside an epic child, grounding, scope ledgers, and
the active change record are written and committed there; post-merge archiving
follows operations.archive.guidance in a sibling archive checkout, which is the
one narrow post-merge exception to this rule and lands through its own reviewed
pull request rather than a push to main. An epic child keeps its
instrumentation in session scratch and relies on its parent record. The control checkout may be dirty, stale, or
on another branch: its working tree is never read or written, and it never
switches branches. Never commit, stash, move, or clean its files, and never
substitute another task's worktree as the control checkout. It holds the
ticket's branch ref, which is what the worktree is cut from. Before its first
write, every verb confirms that its working directory is the path the worktree
helper reported; a mismatch stops the verb.
A chunked order is the one exception and does not loosen the rule: chunk agents
work in per-chunk worktrees cut from the ticket branch and torn down as each
chunk merges back into it, so the ticket still ends with one branch and one
pull request (references/coordinator-mode.md).
Working state lives on the ticket. No scratch directories live on the branch.
Outside an epic, the branch carries shipping code plus the repo's own change
record. An epic child creates no per-child change record; its branch carries
implementation plus any required parent-plan amendment that triage committed,
while the parent epic's active change remains the authority.
Ground in what the repo already says. Read the repo's own decision and
change records, docs/, and recent git log before forming opinions. Read the
standing-decisions source named below when a project configured one.
Status transitions. Verbs move the ticket: triage to triaged, start to
in progress when the branch is cut, start to pending review when the pull
request opens, finalize to done. Status is the contract's one non-fatal
operation: when a move is unavailable or fails, say so in one line and
continue. Never retry a failed move and never force a workaround.
Stop at the pull request boundary. Opening the pull request ends start.
Merging is human. finalize only runs after a human merged.
Fresh-session contract. start assumes no memory of triage. Under a
legacy WORK ORDER, everything it needs must be on the ticket, in the
description plus the work order's own copied prose. Under an
EXECUTION LOCK, self-sufficiency means deterministic acquisition and
verification of the authorized source instead of copied prose, and what that
means depends on the source mode. For openspec and repository-native,
the pinned commit OID plus the lock's own execution-shape fields (session
fit, verification, expected diff) are enough for a fresh session to resolve,
read, and admit the source itself, per start step 5. For
inline, there is no commit to resolve: the fence's own Context/Do/Done when payload is the self-sufficient copy, the same as a legacy order's.
Either way, if what a fresh session needs is not there, that is a triage
defect: refuse and say what is missing.
The verification step
Every order names one verification step and one expectation for its output. The
step is a slot:
- Default: the target repo's own lint and tests, discovered from the repo. Read
its
AGENTS.md or CLAUDE.md for a test command, then its CI workflows, then
its package scripts. Name the command in the order.
- A binding may fill the slot with something stronger. An infrastructure
preview is the worked example: a read-only plan against real state, run locally
before the pull request. When a binding fills the slot, the order's expectation
line describes that tool's output instead of a test result.
- The rule that survives either way: iterate locally until the result is
exactly what the order's expectation says. CI is the check of record, not the
iteration loop.
- Never fabricate expected output. When verification cannot run at all (no
credentials, no access, no runnable suite), say so, open the pull request as a
draft, and name the missing evidence.
The graph identity
Before a verb reads code structurally, it binds its current checkout to exactly one
Codebase Memory project, from that checkout's own path:
python3 <cbm-onboard-skill-directory>/scripts/cbm-lifecycle.py ensure <worktree path>
It prints one object, and the verb reports it verbatim:
{"root_path": "<canonical physical checkout>", "project": "cbm-onboard-v1-<sha256>", "status": "ready"}
ready or indexed: query the graph as exactly that project. Never pick the
graph by project name, branch-like label, list order, apparent recency, or because
it was the only result.
unavailable (exit 2): follow the owning cbm-onboard skill's bounded
supported-version and sandbox retry/fallback sequence first.
An active-generation conflict means wait and retry the same checkout; it is not a
sandbox escalation or authority to close another session. After that owned
sequence is exhausted, say so in one line and use ordinary discovery.
- Any other failure (exit 1): stop the verb and report what
ensure printed on
stderr, which names the cause — a path that is not a checkout, or an installed
tool answering for the wrong project or root. Neither is a case where guessing a
graph is safe.
- The command never ran at all, no exit code, because the harness or sandbox
refused it (a permission classifier declining the Bash call, for example): say so
in one line and use ordinary discovery for the rest of the session, the same as
unavailable.
Every session recomputes this from the checkout it just verified, never from chat
memory or a remembered earlier run. It names one machine's paths, so it never goes
into a work order or any other tracker comment; a chunk agent is handed its own in
its prompt.
Before Git removes a worktree this skill authored, the same directory's
cbm-teardown.sh deletes that checkout's project, while the checkout still exists
for the identity to be derived from. Teardown fails loudly on a machine with no
Codebase Memory installed, which is expected: report it in one line and carry on
with the removal. It never holds up the removal, and it is never retried.
The hardening profile
The target repo declares Harden: <command> beside its test command in repo facts.
Triage stamps Profile: hardening only when that line exists.
It replaces the review rounds as start and revise specify.
A hardening command that cannot run is an error, never a pass.
The profile order's QA script lives in its pull request body.
Standing decisions
A project may point this skill at a knowledge base of standing decisions and
traps to read before grounding in the repo. Its location is the project's to
name: a path in the repo, a file the operator configured, or a page the binding
knows about.
Absent, the verb says so in one line and continues. It never refuses a ticket for
want of it.
The change record
The skill records the change where the target repo already records changes.
Whoever executes the change ticks its checklist as work completes, and a checked
item means implemented and verified, not attempted. That is why a checkbox commit
in a pinned source is the executor's own bookkeeping rather than an amendment
(start step 5).
An epic child creates no per-child change record. Its parent epic owns the active
change and its post-merge archive. Triage may commit a required parent-plan
amendment in the child worktree; start, revise, and coordinator mode preserve the
parent-plan bytes through the implementation pull request, and finalize leaves the
parent active and unarchived.
Outside an epic, follow this per-ticket rule:
- The repo has an OpenSpec layout (
openspec/): write the change folder on the
ticket branch (proposal.md, tasks.md, and design.md when the work
embodies a real decision). Start and revise keep the active change and its
deltas reviewable in the ticket pull request; they do not fold or archive it
before merge. The repository's operations.archive.guidance determines when
finalization archives a verified merge, and the archive itself lands through a
reviewed follow-up pull request that a human merges, never a direct push to the
default branch. /openspec-adopt, when it is installed,
is what adopts OpenSpec in a repo that lacks it. OpenSpec is the worked example,
never a requirement.
- The repo has a different convention (a changelog, a decision-record tree, a
design log): follow that convention exactly as the repo already uses it.
- The repo has no convention: write down what changed and why, where that repo's
readers would look. Do not invent a convention for it.
1---2name: ticket3description: Drive one tracked ticket from arrival to resolution through four verbs: triage, start, revise, finalize. Use when the user says triage/start/revise/finalize with a ticket id, asks to turn a ticket into a locked brief, to action a review round on a ticket's pull request, or to close out a merged ticket. When delegated, the coordinator dispatches every mandatory reviewer and resumes the same worker.4---56# Ticket78One ticket, one verb at a time. Each verb is a full procedure in `verbs/<verb>.md`;9read that file before doing anything else, then follow it. This page holds only10what every verb shares.1112## Invocation1314`/ticket <verb> <ticket-id>`, where verb is `triage`, `start`, `revise`, or15`finalize`. No verb or no ticket id: ask for it, one line. Unknown verb: list the16four.1718## The pipeline1920* `triage` reads the ticket and the repo, interviews the user through `/scope`21 when scope is thin, and ends by posting the **work order**: a locked brief as a22 ticket comment. Work too big for one agent's context is sliced into sub-orders23 in that same comment ([references/slicing.md](references/slicing.md)). It24 writes nothing to the repo except scope and spec documents committed in the25 ticket's worktree. An epic child treats its issue-body order as a draft and may26 commit a required parent-plan amendment in the child worktree before posting the27 reviewed lock; that amendment travels with the implementation pull request.28* `start` runs in a fresh session, fetches the work order, refuses if there is29 none, implements it on a branch in an isolated worktree (or, on a sliced order,30 coordinates one agent per chunk), iterates the verification step until the31 result matches the order's expectation, passes an adversarial review at the32 order's stamped depth ([references/review-depth.md](references/review-depth.md))33 unless `Profile: hardening` replaces it below Full depth,34 opens the pull request, and stops. Agents never merge.35* `revise` actions one review round on the open pull request: reload the ticket36 and the order, fix, re-verify, push.37* `finalize` runs after a human merged: verify the merge and post-merge workflow,38 complete the repository's post-merge archive guidance for an ordinary OpenSpec39 change, which opens a reviewed archive pull request and posts its `Archive PR:`40 locator before stopping, then on a later finalization, once a human merged that41 pull request, close the ticket with a comment linking the pull request, record42 what the ticket actually cost in context, and tear the worktree down, so this43 repo's slicing calibration is tuned against measured numbers rather than44 intuition.4546## The tracker contract4748Every tracker interaction goes through four operations: read a ticket, post a49comment on a ticket, move a ticket's status, and locate the newest work order on50a ticket. [references/tracker-contract.md](references/tracker-contract.md)51defines them, and one binding page supplies them for one tracker. GitHub issues52ship as the reference binding53([bindings/github-issues.md](bindings/github-issues.md)).5455The procedures below and in `verbs/` call the contract, never a tracker's API56directly. A verb that cannot reach the contract stops and names what is missing.5758## Review front door5960`start` and `revise` reach code review as `/review` on the changed code, which61routes to `code-review`. Neither verb calls a reviewer any other way, and neither62substitutes a lighter check for the depth the order stamped. Below Full depth under63`Profile: hardening`, [start](verbs/start.md) and [revise](verbs/revise.md) use its64exception instead.6566## Delegation authority6768This authority covers triage's mandatory `/plan-review` and start/revise's `/review` route. Invoking `/ticket` authorizes every sub-agent dispatch that this procedure marks mandatory, including the coordinator's mandatory reviewer dispatch. Do not ask again solely because a session-level preference says "do not spawn agents"; apply that preference to discretionary delegation only. An explicit task-level refusal of this required review or revocation of delegation overrides this authorization: stop and state that the requested workflow cannot run without its required independent review.6970When Ticket work is delegated, the delegation prompt identifies the71mandatory-review handoff. At that boundary the worker returns or writes its72review-ready result through the coordinator-recorded durable result locator and73does not launch a reviewer. The coordinator dispatches every mandatory reviewer74through the existing adapter after collecting the result, verifies the returned75verdict, and resumes the same worker. Actionable findings resume it for correction; a76verified clean verdict resumes it to finish. A failed launch, nonzero exit,77missing result artifact, or missing verdict is reported as unavailable and blocks78the workflow from advancing as reviewed. Direct nested adapter dispatch by the79worker is unsupported.8081## Selected-ticket mutation boundary8283Triage may mutate operator-local workflow state required by the installed workflow84to execute the selected ticket lifecycle. Current examples include the lifecycle85claim, exact-worktree Codebase Memory state, reviewer-memory store, and local86remote-tracking refs used to resolve and verify the selected ticket's base. These87examples make the purpose concrete; they are not an exhaustive list.8889Triage may also mutate repository or tracker state belonging to the selected ticket90lifecycle without ancillary approval. Current examples include the selected worktree91and branch, an ordinary ticket's active change, the selected ticket's comment and92status, and the defined Epic-child parent-plan amendment carried by that child's93implementation pull request. These examples make the ownership concrete; they are94not an exhaustive list.9596This authority does not authorize state for a distinct external concern:97independently addressable work outside the selected lifecycle, such as another98branch, pull request, issue, ticket, or repository artifact outside the selected99branch. Broad read-only grounding never authorizes it.100101## Shared rules (every verb)1021031. **Open with the ticket summary.** Before any other work, read the ticket and104 give the user an extremely high-level, human-readable summary: what the ticket105 is and what this verb is about to do on it (as simple as "implementing106 `<ticket-id>`, which is `<one-line description>`"). Then mark a chapter titled107 `<ticket-id> <verb>` when the harness offers a chapter tool, so the user can108 scroll back to it. Skip the chapter silently when it does not.1091102. **Claim the session.** Immediately after the ticket summary, run111 `python3 <ticket-skill-directory>/scripts/ticket.py claim <ticket-id> --verb112 <current verb>`, so the113 sessions that worked this ticket are recorded as they work it rather than114 guessed from prose afterwards. Pass `--session` and `--agent` whenever the115 environment cannot answer on its own: no session id in it, or more than one,116 which is what a worker launched from another agent's session sees. Pass117 `--role` to say what the session is doing on the ticket: `coordinator` (the118 session driving the ticket, and the default), `worker` (an agent building one119 chunk), or `reviewer` (a session that only reviews). The role decides which120 costs are evidence about how big the work was, so a session claimed under the121 wrong one is a measurement error. The required `--verb` is `triage`, `start`,122 `revise`, or `finalize`, matching the lifecycle verb this session is running.123 One session serves one lifecycle verb: same-verb resumes reuse the claim, while124 changing verbs requires a fresh session. A cross-verb re-claim keeps and prints125 the persisted claim, reports the persisted and submitted verbs as one visible126 conflict, and exits successfully; telemetry never claims the submitted metadata127 landed. A claim that fails is said in one128 line and never blocks the verb: telemetry is a measurement, not a gate. A129 sandboxed session (a Codex `workspace-write` sandbox, for one) that cannot130 write the claims file under `~/.config/ticket/` sees that one-line denial131 name the path and the fix: rerun the same claim command outside the sandbox132 or with escalated permissions.1331343. **Attribution first.** Every comment this skill posts opens with a one-line135 quote block. With an operator name configured:136137 > Written by an AI agent operating for `<operator>`. Verify before relying on it.138139 With none configured:140141 > Written by an AI agent. Verify before relying on it.142143 The name comes from `~/.config/ticket/config.json`, key `operator`. No file, no144 key, or an empty value all mean the nameless form. Then the content. Never post145 an unattributed comment.1461474. **The lock is the only entry to execution.** A work order is a ticket comment148 whose fence header starts `EXECUTION LOCK ` (any version) or, on a ticket still149 running the legacy protocol, `WORK ORDER`. `start` and `revise` locate it with150 the tracker contract's locate operation151 ([references/tracker-contract.md](references/tracker-contract.md)): newest152 comment wins by post time across both protocols, and no field is ever merged153 from an older comment into a newer one. No order, no execution: refuse and154 route to `/ticket triage <ticket-id>`. Admission is the consumer's job: an155 unrecognized `EXECUTION LOCK` version or `Source:` mode refuses the same way156 rather than falling back to an older comment. A legacy `WORK ORDER` keeps157 today's sufficiency rules with no inferred pin, forever; any supersession uses158 the new protocol.1591605. **One worktree, one branch, per ticket, for the whole lifecycle.** `triage`161 cuts the branch and worktree through `spin-worktree`; `start` and `revise`162 reuse them; `finalize` tears them down. The first repository action after the163 summary-and-claim opening, before grounding or any repo read, is to cut or164 reuse the ticket's worktree. The one pre-worktree exception is fresh epic-child165 triage: it fetches and verifies the issue body's pinned remote parent-plan base,166 then passes that branch to the helper. Outside an epic child, grounding, scope ledgers, and167 the active change record are written and committed there; post-merge archiving168 follows `operations.archive.guidance` in a sibling archive checkout, which is the169 one narrow post-merge exception to this rule and lands through its own reviewed170 pull request rather than a push to `main`. An epic child keeps its171 instrumentation in session scratch and relies on its parent record. The control checkout may be dirty, stale, or172 on another branch: its working tree is never read or written, and it never173 switches branches. Never commit, stash, move, or clean its files, and never174 substitute another task's worktree as the control checkout. It holds the175 ticket's branch ref, which is what the worktree is cut from. Before its first176 write, every verb confirms that its working directory is the path the worktree177 helper reported; a mismatch stops the verb.178 A chunked order is the one exception and does not loosen the rule: chunk agents179 work in per-chunk worktrees cut from the ticket branch and torn down as each180 chunk merges back into it, so the ticket still ends with one branch and one181 pull request ([references/coordinator-mode.md](references/coordinator-mode.md)).1821836. **Working state lives on the ticket.** No scratch directories live on the branch.184 Outside an epic, the branch carries shipping code plus the repo's own change185 record. An epic child creates no per-child change record; its branch carries186 implementation plus any required parent-plan amendment that triage committed,187 while the parent epic's active change remains the authority.1881897. **Ground in what the repo already says.** Read the repo's own decision and190 change records, `docs/`, and recent `git log` before forming opinions. Read the191 standing-decisions source named below when a project configured one.1921938. **Status transitions.** Verbs move the ticket: `triage` to triaged, `start` to194 in progress when the branch is cut, `start` to pending review when the pull195 request opens, `finalize` to done. Status is the contract's one non-fatal196 operation: when a move is unavailable or fails, say so in one line and197 continue. Never retry a failed move and never force a workaround.1981999. **Stop at the pull request boundary.** Opening the pull request ends `start`.200 Merging is human. `finalize` only runs after a human merged.20120210. **Fresh-session contract.** `start` assumes no memory of triage. Under a203 legacy `WORK ORDER`, everything it needs must be on the ticket, in the204 description plus the work order's own copied prose. Under an205 `EXECUTION LOCK`, self-sufficiency means deterministic acquisition and206 verification of the authorized source instead of copied prose, and what that207 means depends on the source mode. For `openspec` and `repository-native`,208 the pinned commit OID plus the lock's own execution-shape fields (session209 fit, verification, expected diff) are enough for a fresh session to resolve,210 read, and admit the source itself, per [start](verbs/start.md) step 5. For211 `inline`, there is no commit to resolve: the fence's own `Context`/`Do`/`Done212 when` payload is the self-sufficient copy, the same as a legacy order's.213 Either way, if what a fresh session needs is not there, that is a triage214 defect: refuse and say what is missing.215216## The verification step217218Every order names one verification step and one expectation for its output. The219step is a slot:220221* **Default:** the target repo's own lint and tests, discovered from the repo. Read222 its `AGENTS.md` or `CLAUDE.md` for a test command, then its CI workflows, then223 its package scripts. Name the command in the order.224* **A binding may fill the slot with something stronger.** An infrastructure225 preview is the worked example: a read-only plan against real state, run locally226 before the pull request. When a binding fills the slot, the order's expectation227 line describes that tool's output instead of a test result.228* **The rule that survives either way:** iterate locally until the result is229 exactly what the order's expectation says. CI is the check of record, not the230 iteration loop.231* **Never fabricate expected output.** When verification cannot run at all (no232 credentials, no access, no runnable suite), say so, open the pull request as a233 draft, and name the missing evidence.234235## The graph identity236237Before a verb reads code structurally, it binds its current checkout to exactly one238Codebase Memory project, from that checkout's own path:239240```sh241python3 <cbm-onboard-skill-directory>/scripts/cbm-lifecycle.py ensure <worktree path>242```243244It prints one object, and the verb reports it verbatim:245246```json247{"root_path": "<canonical physical checkout>", "project": "cbm-onboard-v1-<sha256>", "status": "ready"}248```249250* `ready` or `indexed`: query the graph as exactly that `project`. Never pick the251 graph by project name, branch-like label, list order, apparent recency, or because252 it was the only result.253* `unavailable` (exit 2): follow the owning `cbm-onboard` skill's bounded254 supported-version and sandbox retry/fallback sequence first.255 An active-generation conflict means wait and retry the same checkout; it is not a256 sandbox escalation or authority to close another session. After that owned257 sequence is exhausted, say so in one line and use ordinary discovery.258* Any other failure (exit 1): stop the verb and report what `ensure` printed on259 stderr, which names the cause — a path that is not a checkout, or an installed260 tool answering for the wrong project or root. Neither is a case where guessing a261 graph is safe.262* The command never ran at all, no exit code, because the harness or sandbox263 refused it (a permission classifier declining the Bash call, for example): say so264 in one line and use ordinary discovery for the rest of the session, the same as265 `unavailable`.266267Every session recomputes this from the checkout it just verified, never from chat268memory or a remembered earlier run. It names one machine's paths, so it never goes269into a work order or any other tracker comment; a chunk agent is handed its own in270its prompt.271272Before Git removes a worktree this skill authored, the same directory's273`cbm-teardown.sh` deletes that checkout's project, while the checkout still exists274for the identity to be derived from. Teardown fails loudly on a machine with no275Codebase Memory installed, which is expected: report it in one line and carry on276with the removal. It never holds up the removal, and it is never retried.277278## The hardening profile279280The target repo declares `Harden: <command>` beside its test command in repo facts.281Triage stamps `Profile: hardening` only when that line exists.282It replaces the review rounds as [start](verbs/start.md) and [revise](verbs/revise.md) specify.283A hardening command that cannot run is an error, never a pass.284The profile order's QA script lives in its pull request body.285286## Standing decisions287288A project may point this skill at a knowledge base of standing decisions and289traps to read before grounding in the repo. Its location is the project's to290name: a path in the repo, a file the operator configured, or a page the binding291knows about.292293Absent, the verb says so in one line and continues. It never refuses a ticket for294want of it.295296## The change record297298The skill records the change where the target repo already records changes.299300Whoever executes the change ticks its checklist as work completes, and a checked301item means implemented and verified, not attempted. That is why a checkbox commit302in a pinned source is the executor's own bookkeeping rather than an amendment303([start](verbs/start.md) step 5).304305An **epic child** creates no per-child change record. Its parent epic owns the active306change and its post-merge archive. Triage may commit a required parent-plan307amendment in the child worktree; start, revise, and coordinator mode preserve the308parent-plan bytes through the implementation pull request, and finalize leaves the309parent active and unarchived.310311Outside an epic, follow this per-ticket rule:3123131. The repo has an OpenSpec layout (`openspec/`): write the change folder on the314 ticket branch (`proposal.md`, `tasks.md`, and `design.md` when the work315 embodies a real decision). Start and revise keep the active change and its316 deltas reviewable in the ticket pull request; they do not fold or archive it317 before merge. The repository's `operations.archive.guidance` determines when318 finalization archives a verified merge, and the archive itself lands through a319 reviewed follow-up pull request that a human merges, never a direct push to the320 default branch. `/openspec-adopt`, when it is installed,321 is what adopts OpenSpec in a repo that lacks it. OpenSpec is the worked example,322 never a requirement.3232. The repo has a different convention (a changelog, a decision-record tree, a324 design log): follow that convention exactly as the repo already uses it.3253. The repo has no convention: write down what changed and why, where that repo's326 readers would look. Do not invent a convention for it.