Ticket
SkillDev toolsDrive 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.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Ticket skill
What this skill tells your AI
The instructions your AI receives, as published by connorgriffin/skills in skills/drivers/ticket/SKILL.md and read by ahel’s review.
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
triagereads the ticket and the repo, interviews the user through/scopewhen 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.startruns 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) unlessProfile: hardeningreplaces it below Full depth, opens the pull request, and stops. Agents never merge.reviseactions one review round on the open pull request: reload the ticket and the order, fix, re-verify, push.finalizeruns 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 itsArchive 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--sessionand--agentwhenever 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--roleto say what the session is doing on the ticket:coordinator(the session driving the ticket, and the default),worker(an agent building one chunk), orreviewer(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--verbistriage,start,revise, orfinalize, 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 Codexworkspace-writesandbox, 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, keyoperator. 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.startandreviselocate 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 unrecognizedEXECUTION LOCKversion orSource:mode refuses the same way rather than falling back to an older comment. A legacyWORK ORDERkeeps 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.
triagecuts the branch and worktree throughspin-worktree;startandrevisereuse them;finalizetears 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 followsoperations.archive.guidancein 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 tomain. 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 recentgit logbefore forming opinions. Read the standing-decisions source named below when a project configured one. -
Status transitions. Verbs move the ticket:
triageto triaged,startto in progress when the branch is cut,startto pending review when the pull request opens,finalizeto 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.finalizeonly runs after a human merged. -
Fresh-session contract.
startassumes no memory of triage. Under a legacyWORK ORDER, everything it needs must be on the ticket, in the description plus the work order's own copied prose. Under anEXECUTION 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. Foropenspecandrepository-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. Forinline, there is no commit to resolve: the fence's ownContext/Do/Done whenpayload 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.mdorCLAUDE.mdfor 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"}
readyorindexed: query the graph as exactly thatproject. 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
ensureprinted 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, anddesign.mdwhen 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'soperations.archive.guidancedetermines 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.
Signals
- GitHub stars
- 20
- Forks
- 5
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
ticket- Source
- github.com/connorgriffin/skills