Skip to content

feat(wrap-up): plan-aware branching — emit resume blocks when plan is incomplete#329

Merged
JacobPEvans merged 4 commits into
mainfrom
feat/wrap-up-resume-mode
May 25, 2026
Merged

feat(wrap-up): plan-aware branching — emit resume blocks when plan is incomplete#329
JacobPEvans merged 4 commits into
mainfrom
feat/wrap-up-resume-mode

Conversation

@JacobPEvans
Copy link
Copy Markdown
Owner

@JacobPEvans JacobPEvans commented May 25, 2026

Summary

  • /wrap-up now runs a new Step 0 before the existing cleanup pipeline to decide whether this session's plan is actually done.
  • Path A (plan complete or absent) is byte-identical to the prior behavior: /refresh-repo, /retrospecting quick, /clean_gone, then a forward-looking follow-up prompt.
  • Path B (plan incomplete) skips Path A — refresh-repo would prune the in-flight worktree — and emits one or more copy-paste Resume Blocks: cd <worktree> plus a self-contained prompt that points at the plan file, lists remaining checklist line numbers + TaskList task IDs, and notes what was already done so a fresh session does not redo work.
  • Resume Blocks group by judgement, not by repo alone: same repo + same goal stays together; same repo + unrelated threads split; cross-repo always splits.
  • /wrap-up purge-pr <PR> is unchanged and still bypasses Step 0.

Why this matters

The prior /wrap-up assumed the session ended cleanly post-merge. Invoking it mid-plan (context exhaustion, blocker, machine switch) buried unfinished work in the forward-looking follow-up prompt alongside speculative future ideas, which made resuming the exact plan hard. Path B is built for that case.

Identifying the current session's plan

Plan identification uses the plan-mode <system-reminder> already in this session's conversation as the single source of truthnever ~/.claude/plans/ mtime. mtime races under heavy parallelism (many concurrent sessions on the same machine). TaskList is intrinsically session-scoped by the harness, so it is read directly without disambiguation. The path-matching regex is generic ([^[:space:]]+/\.claude/plans/[^[:space:]]+\.md) so the skill works for every plugin user, not one specific home.

URL rule for emitted PR/issue references

Every PR or issue referenced in wrap-up output must use the full https://github.com/<owner>/<repo>/(issues|pull)/<n> URL on first mention — never bare #123, which forces the reader to guess the repo. Codified in the A4c triage step (captures gh issue list --json url), the A4d output template, and the Path B Resume Block "must include" list.

CI / local-validation change

Added cclint (github.com/dotcommander/cclint) as a local precommit hook in .pre-commit-config.yamlthis repo only. Mirrors the loop in .github/workflows/validate-plugin.yml so frontmatter validator failures (e.g. angle brackets in description) fail at commit time instead of escaping to CI. Uses pre-commit's language: golang so contributors do not need a host Go toolchain — pre-commit installs cclint into an isolated env. Loop logic lives in scripts/cclint-plugins.sh per the no-inline-scripts rule.

Verified locally: re-injecting <repo> into the SKILL.md description reproduces the exact CI error message and blocks commit.

Commits

SHA Subject
be4ed5a feat: Step 0 + Path A/B routing + Resume Block format
f204dff fix: strip <repo> angle brackets from description; URL rule; add cclint precommit hook
11700e4 fix: generalize plan-path prose and regex — no user-specific homes (addresses gemini-code-assist review)

Test plan

All verification is human-driven against real Claude Code sessions — no automated tests exist for this skill (it composes other skills + reasoning). CI covers markdown lint, cclint frontmatter validation, and CodeQL.

  • Path A regression — fresh session, no plan mode, trivial task, invoke /wrap-up. Expect identical behavior to today.
  • Path B basic — session enters plan mode, writes plan with one unchecked item, exits plan mode, does not implement, invokes /wrap-up. Expect one Resume Block citing the exact plan path + Path A skipped + incomplete summary.
  • Path B multi-block grouping — plan touching two repos. Expect two blocks with distinct cd paths and self-contained prompts.
  • Parallelism regression — two sessions back-to-back, both in plan mode against different plan files; invoke /wrap-up in session A with A's work incomplete. Expect A's plan path cited, never B's, even though B's file is more recently modified on disk.
  • purge-pr unchanged/wrap-up purge-pr <PR> against a throwaway branch. Expect Step 0 bypassed entirely.
  • cclint regression — temporarily inject <foo> into any SKILL.md description, run pre-commit run cclint-plugins --all-files, confirm it fails with the Anthropic validator's error message.

🤖 Generated with Claude Code

…ncomplete

Add Step 0 that decides whether this session's plan is actually done before
running the standard cleanup pipeline.

Plan identification uses the plan-mode `<system-reminder>` already injected
into the conversation as the SSOT — never mtime, which races under heavy
parallelism. TaskList is session-scoped by the harness, so it is safe to read
directly. A plan is complete iff every TaskList task is `completed` AND every
plan-file checklist item is checked (or has clear conversation evidence of
completion), or no plan file exists for this session.

- Path A (plan complete or absent): identical to the prior behavior — invoke
  `/refresh-repo`, `/retrospecting quick`, `/clean_gone`, emit forward-looking
  follow-up prompt.
- Path B (plan incomplete): skip Path A (refresh-repo would prune the in-flight
  worktree) and emit one or more Resume Blocks. Each block is a `cd <worktree>`
  plus a self-contained prompt that re-points at the plan file, lists remaining
  checklist line numbers and TaskList task IDs, and notes what is already done
  so a fresh session does not redo work. Items are grouped by judgement, not
  blindly by repo: same repo + same goal stays together, same repo + unrelated
  threads split, cross-repo always splits.

`/wrap-up purge-pr <PR>` is unchanged and still bypasses Step 0.

Plan: ~/.claude/plans/update-wrap-up-so-that-cozy-quasar.md

Assisted-by: Claude <noreply@anthropic.com>
Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the wrap-up skill definition to support a dual-path workflow depending on whether the current session's plan is complete (Path A for clean wrap-up, Path B for emitting resume blocks). The review feedback correctly points out that the plan file paths and regex patterns are hardcoded to a specific user's home directory (/Users/jevans) and provides suggestions to make them generic and environment-agnostic.

Comment thread git-workflows/skills/wrap-up/SKILL.md Outdated
Comment thread git-workflows/skills/wrap-up/SKILL.md Outdated
Comment thread git-workflows/skills/wrap-up/SKILL.md Outdated
… PR/issue refs

The prior commit's frontmatter description contained `cd <repo>` literally.
Anthropic's plugin validator (cclint) rejects angle brackets in `description`,
which surfaced as a CI validate-plugin failure. Reworded to "cd-into-worktree
blocks" — same meaning, no brackets.

While here, codify a URL rule the user requested for any wrap-up output that
references PRs or issues: emit the full
`https://github.com/<owner>/<repo>/(issues|pull)/<n>` URL on first mention,
never bare `#123`. The triage step now captures the `url` field from
`gh issue list`, and the Resume Block template explicitly requires URLs for
referenced PRs/issues.

ci(precommit): add cclint as a local hook so the description-validator failure
that escaped to CI on the prior commit fails at commit time instead. Uses
pre-commit's `language: golang` to install
`github.com/dotcommander/cclint@latest` into an isolated env — no Go toolchain
on the host required. Logic lives in scripts/cclint-plugins.sh per the
no-inline-scripts rule, mirroring the loop in
.github/workflows/validate-plugin.yml.

Verified locally: pre-commit run cclint-plugins --all-files passes on the
fixed tree, and re-injecting `<repo>` into the description reproduces the
exact CI error message.

Assisted-by: Claude <noreply@anthropic.com>
gemini-code-assist flagged three SKILL.md sites that hardcoded
`/Users/jevans/.claude/plans/...` paths and regex patterns. The plugin is
published to the public marketplace, and the workspace secrets-policy bans
committed user-specific paths. The matching regex in 0a would also never
fire for any other plugin user.

- Frontmatter Step 0a prose: describe the path shape generically
  (`<HOME>/.claude/plans/<slug>.md`) instead of naming one home.
- 0a regex: `[^[:space:]]+/\.claude/plans/[^[:space:]]+\.md` — matches any
  absolute path ending under `.claude/plans/`, not just one user's home.
- Path B Resume Block template: example path is `~/.claude/plans/<slug>.md`
  with a note to substitute the resolved absolute path emitted by the
  plan-mode system reminder.

Refs: gemini-code-assist review threads on
#329

Assisted-by: Claude <noreply@anthropic.com>
@JacobPEvans JacobPEvans changed the title feat(wrap-up): branch on plan completeness; emit resume blocks when incomplete feat(wrap-up): plan-aware branching — emit resume blocks when plan is incomplete May 25, 2026
Three corrections after review:

1. SKILL.md prose conflated "the plan file" with "the system reminder".
   The plan file at ~/.claude/plans/<slug>.md is the real document on
   disk and the canonical store of plan content; the plan-mode
   <system-reminder> is the deterministic *binding* from session to
   file, which is what the parallelism-safe lookup needs. Step 0's
   intro now separates the two concepts and points Step 0a at the
   binding problem specifically.

2. scripts/cclint-plugins.sh was unnecessary. cclint ships a --staged
   git-integration mode designed for pre-commit (and a --diff mode for
   uncommitted changes). It reads files from the git index, detects
   each file's plugin context (e.g. <plugin>/skills/<name>/SKILL.md),
   and validates accordingly. Bare `cclint` from the repo root only
   scans the root-level agents/commands/skills/output-styles dirs and
   silently misses per-plugin SKILL.md issues — confirmed by injecting
   `<repo>` into a description and watching `cclint` pass while
   `cclint --staged` correctly fails. Hook entry is now
   `cclint --staged`, no wrapper.

3. The trigger glob covered commands/agents, but only skills are an
   active plugin component in this repo. Glob narrowed to
   `^[^/]+/(skills/.*\.md$|\.claude-plugin/plugin\.json$)`.

Verified by staging a description with literal `<repo>` and attempting
`git commit`: hook fails with the exact CI error message and blocks
the commit. Reverting the description and re-committing succeeds.

Assisted-by: Claude <noreply@anthropic.com>
@JacobPEvans JacobPEvans merged commit 28916c8 into main May 25, 2026
8 checks passed
@JacobPEvans JacobPEvans deleted the feat/wrap-up-resume-mode branch May 25, 2026 21:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant