Checkpoint
Lightweight mid-task save: commit work-in-progress to git and post a progress update to the Linear issue.
Arguments
- Issue identifier (e.g.,
PL-12) — optional, auto-detected from branch name or latest commit no push/don't push/skip push— optional, skips the git push step (commit still happens)
Examples: /checkpoint, /checkpoint PL-12, /checkpoint no push, /checkpoint PL-12 no push
Workflow
Preflight: Exit Plan Mode If Active
If the session is in plan mode when /checkpoint is invoked, call ExitPlanMode before any other step. Step 1 onward needs Bash (detect-issue-id.sh, git status, git commit, etc.) and Write — all blocked in plan mode — so the first script call would fail otherwise.
Detection. Use the harness's plan-mode indicator visible at skill entry (the same signal that was gating tool calls just before this skill loaded). If that indicator is ambiguous or unavailable, attempt Step 1; if detect-issue-id.sh fails with a plan-mode block, return here, call ExitPlanMode, then retry Step 1. Do NOT speculatively call ExitPlanMode when plan mode is not active — it raises a spurious approval prompt the user must dismiss.
Plan body. Pass a one-line plan summarizing what /checkpoint is about to do. There is nothing to design — /checkpoint is a fixed mechanical workflow — but ExitPlanMode is the only way to leave plan mode and it requires a plan body. For the <ISSUE-ID> substitution: only inline a user-supplied token if it matches ^[A-Z]+-[0-9]+$ (case-insensitive, uppercase it before substituting); otherwise use the current branch's issue. This keeps malformed tokens out of the plan body and out of any rejection-terminator that echoes the same value.
- Approved by the user: proceed to Step 1.
- Rejected by the user: proceed to the rejection terminator below.
- Tool-error / harness failure (not a user rejection — the tool itself returns an error, or the harness reports
ExitPlanModefailed for a non-user-cancel reason): surface the error verbatim and stop withIN-PROGRESS: <ISSUE-ID or "current branch"> — ExitPlanMode failed at /checkpoint preflight: <first line of error>. WARNING: no commit, no Linear update. Resolve and re-run /checkpoint.Do NOT continue to Step 1; plan mode is still active and Step 1 will compound the failure.
On user rejection via the approval UI, treat as an abort and stop with:
IN-PROGRESS: <ISSUE-ID or "current branch"> — user rejected /checkpoint at the plan-mode preflight. No commit, no Linear update.
IN-PROGRESS is the right tag because no state changed — the issue truly is still in progress. Do not retry, do not re-prompt, do not run any subsequent step. Skip this preflight only when plan mode is NOT active — /checkpoint is normally invoked from a non-plan session during active development, in which case this section is a no-op.
Step 1: Identify the Issue
~/.claude/scripts/detect-issue-id.sh [--input <USER-SUPPLIED-ID>]
The script tries --input → current branch → latest commit subject, in that order. Pass --input only when the user typed an explicit ID (e.g., /checkpoint PL-12). On exit 1, ask the user for the identifier explicitly.
Step 2: Branch Safety
Verify we're NOT on main or master. Checkpoint is for feature branches only — refuse and explain if on a protected branch.
Step 3: Verify Changes Exist
git status
If there are no staged or unstaged changes (working tree is clean), warn the user that there's nothing to checkpoint and exit. A checkpoint without code changes isn't a checkpoint.
Step 4: Get Issue Details
linear-cli issues get PL-42
Read the description. Note:
- Title (for commit message)
- Requirement checkboxes (
- [ ]items)
Step 5: Update Completed Checkboxes
If any - [ ] checkboxes have been completed, update them now.
# Get current description as JSON
linear-cli issues get PL-42 --output json
For each - [ ] checkbox in the description:
- If completed: replace with
- [x] - If not completed: leave as
- [ ]
If any checkboxes changed, update the description:
- Use the
Writetool to save the full updated description totmp/linear-description-<issue-id-lowercased>.md(e.g.,tmp/linear-description-pl-42.md) - Run:
~/.claude/scripts/linear-post.sh description PL-42 tmp/linear-description-pl-42.md
Important: Preserve the entire description — only change - [ ] to - [x] for completed items. Do not rewrite or reformat.
Skip this step entirely if no checkboxes changed.
Step 6: Check Status (non-blocking)
pnpm check
Record whether checks pass or fail. Do NOT gate on this — it's WIP. If checks fail, note which checks failed for the Linear comment. Continue regardless.
Step 7: Git Commit & Push
Invoking /checkpoint IS the commit/push grant for this one WIP checkpoint — see
Git Standards § Named exceptions. It is bounded to the named issue's
change set, staged by name; the push half is suppressible with no push. It grants nothing beyond
this invocation.
Stage relevant changed files by name (never git add . or git add -A).
Commit message format: checkpoint: <brief summary> [<ISSUE-ID>]
- Imperative mood, lowercase after prefix
- Include issue key in brackets for traceability
- Example:
checkpoint: add auth middleware and route guards [PL-42]
git add <specific-files>
git commit -m "checkpoint: <summary> [PL-42]"
Then push to remote (unless no push was requested):
git push
If the user requested no push, skip and inform: "Skipping push as requested. Push manually when ready: git push"
Step 8: Post Linear Comment
Write a checkpoint comment summarizing progress. Structure:
## Checkpoint
### Completed
- [bullet points of what's done so far]
### In Progress
- [what's partially done]
### Remaining
- [what's left to do]
### Check Status
✅ All checks pass / ⚠️ Failures: [list failing checks]
### Commit
`<short-sha>` on branch `<branch-name>`
Omit empty sections. Keep it concise — this is a status update, not a report.
- Use the
Writetool to save the comment totmp/linear-checkpoint-<issue-id-lowercased>.md(e.g.,tmp/linear-checkpoint-pl-42.md). - Run:
~/.claude/scripts/linear-post.sh comment <ISSUE-ID> tmp/linear-checkpoint-<issue-id-lowercased>.md
Step 9: Tagged Final Line
After Step 8 posts the Linear comment, emit the tagged final line per standards/lifecycle-tags.md as the last LLM-authored output. /checkpoint always ends with IN-PROGRESS: since the issue stays in In Progress and work is expected to resume.
Every <...> token in the templates below is a substitution site — replace each with the resolved value before emitting; never write a literal <placeholder> to chat. <ISSUE-ID> is uppercase (e.g., PL-42); <issue-id-lowercased> is lowercase (e.g., pl-42) and MUST match the filename Step 8 wrote.
Inspect the exit code from Step 8's linear-post.sh invocation to decide which branch fires below. If the bash exit code was non-zero, take the "Step 8 failed" branch even if the prose output looks partially normal — non-zero is the signal that matters.
Step 8 succeeded (linear-post.sh exited 0):
IN-PROGRESS: <ISSUE-ID> — <one-line progress summary: e.g., "3 of 5 requirement checkboxes complete; paused mid-implementation.">
The summary should match what was just posted to Linear (so the agents-list and Linear stay in sync). For multi-section comments, distill the most recent ### Completed count or the most-significant in-progress item — one line, not a paraphrase of the whole body.
Step 8 failed (linear-post.sh exited non-zero — auth dropped, network blip, Linear outage): do NOT silently emit a tag claiming success. Surface the staging-file path so the user can recover, then emit:
IN-PROGRESS: <ISSUE-ID> — <one-line progress summary>. WARNING: Linear comment NOT posted (linear-post.sh failed; see error above). Staging file preserved at tmp/linear-checkpoint-<issue-id-lowercased>.md — re-post manually with: ~/.claude/scripts/linear-post.sh comment <ISSUE-ID> tmp/linear-checkpoint-<issue-id-lowercased>.md
The agents-list still shows IN-PROGRESS: (work IS in progress), but the inline WARNING makes the de-sync visible so the user doesn't assume Linear was updated.
Do not emit any trailing prose after the tagged line.
Key Differences from /finish
| Aspect | /checkpoint | /finish |
|--------|-------------|---------|
| pnpm check | Non-blocking (report only) | Hard gate |
| Issue state | No change (stays In Progress) | Moves to Ready For Release |
| Checkboxes | Update completed ones | Update all completed ones |
| Git push | Default on, no push flag | Default on, no push flag |
| Linear comment | Progress snapshot | Completion summary |
| Scope | Quick save | Full completion workflow |
Error Handling
- On main/master: Refuse — "Checkpoint is for feature branches. Switch to a feature branch first."
- No changes: Warn — "Nothing to checkpoint. Working tree is clean." Exit.
- No issue found: Ask the user for the issue identifier.
linear-clinot authenticated: Promptlinear-cli auth oauth.- Push fails: Warn but don't fail — the commit is saved locally. User can push later.
- Linear post fails (Step 8
linear-post.shexits non-zero): Surface the error to the user, preserve the staging file (tmp/linear-checkpoint-<issue-id-lowercased>.md), and proceed to Step 9 — which inspects the exit code and emitsIN-PROGRESS:with an inline WARNING that Linear was NOT updated and a recovery command. Do not silently emit a cleanIN-PROGRESS:(the agents-list would then claim success while Linear has no record of the checkpoint).