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.
Scanned 9/4/2026
Install to Claude Code
npx -y skills add ConnorGriffin/skills --skill ticket --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Ticket?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/connorgriffin-ticket)More formats (shields.io, HTML) on the badges page.
---
name: ticket
description: "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."
---
# 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](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](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](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](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](verbs/start.md) and [revise](verbs/revise.md) 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)
1. **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.
2. **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.
3. **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.
4. **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](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.
5. **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](references/coordinator-mode.md)).
6. **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.
7. **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.
8. **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.
9. **Stop at the pull request boundary.** Opening the pull request ends `start`.
Merging is human. `finalize` only runs after a human merged.
10. **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](verbs/start.md) 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:
```sh
python3 <cbm-onboard-skill-directory>/scripts/cbm-lifecycle.py ensure <worktree path>
```
It prints one object, and the verb reports it verbatim:
```json
{"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): no usable Codebase Memory here, so say so in one line and
use ordinary discovery for the rest of the session.
* 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](verbs/start.md) and [revise](verbs/revise.md) 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](verbs/start.md) 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:
1. 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.
2. 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.
3. 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.
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!