Skip to main content

tk-workflow

The trapperkeeper workflow -- names, branches, commits, issues, plans, the GitHub tools and the four stages a unit of work moves through with the owner's invocation as the gate between them. Loaded by the seed skills and at the top of every stage skill; never invoked by the owner.

Source facts

Repository
solatis/trapperkeeper
Last source activity
October 31, 2026 at 11:21
Detected SKILL.md language
English
Stars
0
Forks
0

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
tk-workflow
description
The trapperkeeper workflow -- names, branches, commits, issues, plans, the GitHub tools and the four stages a unit of work moves through with the owner's invocation as the gate between them. Loaded by the seed skills and at the top of every stage skill; never invoked by the owner.
user-invocable
false
# The trapperkeeper workflow ## Units and issues - An **issue** is one right-sized piece of work: one subject, mergeable on its own, about 3 to 10 build commits. It has one branch, one pull request and one plan, and it moves through the stages on its own. - A **unit** is the set of issues the owner chose to do in one go. It exists only in the session; GitHub has no object for it. Its value is shared context: one context load and one challenge round cover all its issues. - A **milestone** holds goals, never a plan. Issues are cut from what the active milestone's goals still need, at scoping time, one unit at a time. An issue without a milestone is free-form work and is equally valid. - Milestones carry no due dates (owner, 2026-10-31). Their order is their GitHub number, which is creation order, and the active milestone is the open one with the lowest number. A milestone's description is its goal and a "done when" list; it is edited in place as the work teaches more. Every stage skill takes a set of issues: the ones named in its argument, or else the issues of the unit in this session. ## Names Fixed once, in the seed report, and copied verbatim afterwards; never retyped or reworded. A session without the seed report reads them from the plan's header lines. | Artifact | Form | Example | | ----------- | ---------------------------------------------------- | ----------------------------------- | | Issue title | imperative or noun phrase, capitalized, no period | `Structured logging for the server` | | Slug | kebab-case, 2 to 5 words, unique among open branches | `server-logging` | | Branch | the slug, no prefix, no issue number | `server-logging` | | Plan | `.plans/<slug>-plan.md` | `.plans/server-logging-plan.md` | | PR title | `type(scope): subject`, one line | `feat(server): add structured logs` | | Commits | `type(scope): subject`, one line | `feat(server): emit json log lines` | ## Branches and commits - `master` is the base. It receives commits only by fast-forward from a feature branch whose head was reviewed and built green. Its history is flat and linear; it stays that way. - An issue's branch starts from its **base**: `master` up to date with origin, or, for a stacked issue, the branch of the issue it depends on. The plan's `Base:` line names it. - Commits are small and individual: one line, `type(scope): subject`, type in feat, fix, chore, refactor, docs, test, perf, build, ci; no body, no trailers, no AI attribution. Each commit builds and passes lint and tests on its own, because every one of them lands on `master` as it is. - Pull requests: `gh pr create -B <base> -t "<PR title>" -b ""`. The body stays empty. No reviewer: the owner reviews through plannotator. - No squash-merge, no merge commits, no force-push to `master`. A feature branch is rebased and force-pushed (`--force-with-lease`) only where a stage skill says so; the owner's invocation of that stage is the request. ## Reading the tree Every stage starts by reading the tree, the plans and GitHub. Read the state as it is, not as a story: a merged issue is a fast-forward, so its commits sit on master with no merge commit, its branch is gone, its issue is closed and its plan is deleted; that is the workflow working. A leftover is a dirty tree, master behind origin, a local branch whose PR is merged or closed, or a plan whose issue is closed. In the seed stage each leftover is a line under Open questions, not a reason to stop, unless it is the branch or plan of an issue in the unit; in the later stages the stage's entry check says what a leftover means. ## Plans - One plan per issue, `.plans/<slug>-plan.md`. `.plans/` is gitignored: a plan is never committed, never pushed, and never part of a diff. plannotator reads it from disk. - The plan starts with these header lines, which are how every stage finds an issue's branch, base, title and state: ``` Issue: #<n> Branch: <slug> Base: master | <slug of the issue it depends on> PR title: <type(scope): subject> Status: draft | approved ``` - The plan is the only memory of its issue across sessions. It exists on this machine only: a fresh worktree or another machine does not have it. - The plan is deleted by the merge stage, after its issue lands. By then every reason it carried is in a comment or a document; the build stage's `/doc-discipline check` against the plan makes sure of that. ## Tools The stage skills say what to do; these skills say how: | Concern | Skill and section | Values here | | -------------- | ------------------------------------------------------------------------- | ------------------------------------------------------------- | | Pull requests | `~/.claude/skills/github/`, "Create", "Inspect" | repo `solatis/trapperkeeper`, resolved by `gh` from the clone | | CI | `~/.claude/skills/github/`, "Watching checks" | `scripts/gh-watch.sh <sha>`, `CHECKPOINT=7200` | | Merging | `~/.claude/skills/github/`, "Fast-forward merge", "Stacked pull requests" | base `master` | | Rebasing | `~/.claude/skills/github/`, "Review follow-ups" | only where a stage skill says so | | Plan gate | `plannotator annotate <plans...> --gate --json` | all plans of the unit in one session | | Code review | `plannotator review --base <base> --json`, on the checked-out branch | one PR per session | | Comment policy | `/doc-discipline` | `read` before writing; `check <paths> <plan>` before the push | `CHECKPOINT=7200` because the watcher runs beside a plannotator review that can take hours. plannotator runs one session at a time: a session opened while another is up comes back `dismissed`, so no two ever overlap. Every plannotator command runs in the background with `timeout` 7200000 ms, the harness's cap, and blocks until the owner decides; the harness wakes you when it exits. A session the time limit stops is run again with the same command; the owner's drafts are restored. With a `plannotator` tool in the session, call it with the same target and `gate: true` instead of the CLI; it returns the same decision. The `quasardb-workflow`, `shortcut` and `buildkite` skills do not apply in this repository, nor do the github skill's "Squash-merge" and "Cherry-pick after merge" sections. Correct: the build stage pushes `server-logging`, opens its PR against `master`, and runs `gh-watch.sh` with the head's SHA and `CHECKPOINT=7200` in the background. Incorrect: the owner's message says "merge", and the session squash-merges the PR through `gh pr merge --squash`, because that is what the github skill describes first. ## Lifecycle: four stages, three gates Every issue moves through these stages in order. Each stage is a skill the owner invokes; the invocation is the gate. A chat message ("go", "ok", "yes", "proceed", "looks good", a thumbs up) opens no stage, whatever its wording: it answers a question inside the current stage, or it is a review comment on what the current stage produced. | Stage | Opened by | You produce | You never | Ends with | | -------- | -------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | | 1. Seed | `/tk-start <task or #n>` or `/tk-start-next` | the seed report | write, create issues, branch, commit | a wait for `/tk-plan` | | 2. Plan | `/tk-plan` | the GitHub issues that do not exist yet, one plan per issue, the gate on all of them, and on approval `Status: approved` in each | touch code, tests, config or any tracked file; branch; commit | the plan-stage message, then a wait for `/tk-build` | | 3. Build | `/tk-build` | per issue: the branch, the plan's commits, the doc-discipline runs, the push, the PR, its CI run and its plannotator review | merge; deviate from a plan without saying so; invent a reason for a comment; ask about merging before green | the build-stage message, then a wait for `/tk-merge` | | 4. Merge | `/tk-merge` | per PR in dependency order: the fast-forward, the push of `master`, the branch deletion, the issue closed, the plan deleted | merge a head that is not the reviewed, green head; merge without the owner having invoked `/tk-merge` | one line per merged PR | A session may begin at any stage from the tree, the plans and GitHub. `/tk-start #<n>` reads where an issue stands and names the next gate; it opens nothing. `/tk-build` and `/tk-merge` take the plans and GitHub as their whole input and need no seed or plan conversation. Stages apply per issue. The owner may open `/tk-merge #12` while `#13` is still in review; a stage never waits for the rest of its unit. Open questions the owner left unanswered are not answered by a stage opening; the plan records your recommendation for each, and the gate's approval is what settles them. Correct: the seed report is posted and the owner writes "looks good". You answer that you are waiting for `/tk-plan`, and do nothing else. Incorrect: the seed report is posted, the owner writes "go", and you create the issues and write the plans, because "go" sounded like the gate. Or: the plan gate returns `approved` and you create the first branch. A small change and a settled design do not shorten the lifecycle; each gate exists so the owner reviews one stage's output on its own.
View on GitHub