Skip to content

feat: promote /prepare-compact into vault-cli plugin (spec 034) - #95

Merged
bborbe merged 3 commits into
masterfrom
feat/prepare-compact-plugin-command
Aug 19, 2026
Merged

feat: promote /prepare-compact into vault-cli plugin (spec 034)#95
bborbe merged 3 commits into
masterfrom
feat/prepare-compact-plugin-command

Conversation

@bborbe

@bborbe bborbe commented Aug 19, 2026

Copy link
Copy Markdown
Owner

Promotes /prepare-compact from the per-machine ~/.claude/commands/ directory into the plugin as /vault-cli:prepare-compact, so it ships via normal plugin install/update instead of living on one machine.

Why vault-cli

The command's only writes are vault progress updates — a vault-cli:sync-progress call plus a sweep of touched goal/task pages — plus the per-session checkpoint file. The git/docker/dark-factory checks are read-only reporting that annotate the verdict, not actions. That puts it in the vault lifecycle namespace beside session-close, sync-progress, and update-task.

Changes

  • commands/prepare-compact.md — new command, all six steps preserved
  • CHANGELOG.mdfeat: bullet under ## Unreleased
  • specs/in-progress/034-prepare-compact-plugin-command.md + generated prompt

Notable

allowed-tools is now granular, not bare Bash. This makes the read-and-report-only invariant capability-enforced rather than prose-only — the command structurally cannot commit, push, or kill anything. Note this required adding the Write tool and Bash(mkdir:*): the source's bare Bash was silently covering the checkpoint file write, which granular scoping would otherwise have broken at runtime.

One acceptance criterion was fixed during audit. The original AC demanded grep -c '⚪ DONE' return 0, but the source contains that string once — inside the safety instruction "Do NOT emit a ⚪ DONE / session-close panel." A faithful port could not pass it, and the cheapest workaround would have been rewording the safety rule to dodge the grep. Now requires exactly 1, with a separate negative check (👤 You: count 0) that catches an actually-emitted panel.

Verification. All 16 load-bearing strings confirmed present in the produced file, including the stopped-daemon warning and the || echo "no daemon" shell fallbacks. The container cannot read the original source file (it lives outside the repo), so the port is reconstructed from the spec's quoted strings — hence the direct string-level verification rather than trusting precommit alone.

The restructure (numbered steps → ## sections) left four dangling "step N" cross-references pointing at steps the file no longer has; fixed in the follow-up commit.

Out of scope

Fate of the local ~/.claude/commands/prepare-compact.md duplicate — tracked separately; nothing outside this repo is touched.

@ben-s-pull-request-reviewer ben-s-pull-request-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Now I have enough context to produce the review. The mechanical funnel found zero findings across 74 rule YAMLs. The changed files are all markdown/documentation (command docs, spec, prompt record, changelog) — no code files. The selector-mode short-circuit applies.

Step 4 short-circuit: applicable set is empty AND mechanical findings are zero → selector clean — no adjudication needed.

Proceeding to Step 5 with my manual review of the changed files.


PR Review: feat/prepare-compact-plugin-commandmaster

Changed files (from diff stat)

File +Lines Purpose
CHANGELOG.md +4 ## Unreleased feat bullet
commands/prepare-compact.md +102 New slash command
prompts/completed/185-*.md +229 Dark-factory prompt execution record
specs/in-progress/034-*.md +132 Spec

Step 3a — LICENSE

LICENSE file present at repo root. ✓

Step 3b — precommit (selector mode)

Skipped — selector mode defers lint/test to CI. ✓

Step 4 — Mechanical funnel

ast-grep-runner: 0 findings across 74 rule YAMLs. ✓

Step 4 (selector) — Candidates

Changed files are all markdown/YAML metadata — no go, py, js, ts, sh source files. No judgment-rule glob matches. Selector clean — no adjudication needed.


Manual Review (changed files only)

commands/prepare-compact.md

Security modelallowed-tools is correctly granular:

  • No bare Bash, no Edit, no Task, no AskUserQuestion
  • Six scoped read-only/status Bash subcommands only: git status:*, git log:*, git rev-parse:*, pgrep:*, dark-factory status:*, docker ps:*
  • mkdir:* only for creating the checkpoint directory
  • Write for checkpoint file; Skill for sibling call; Read/Glob for vault traversal
  • This is the correct pattern — the tool surface cannot commit, push, or kill even if prose is misread. ✓

Session-id trust boundary — correctly derived from the session's own scratchpad path, not from user input or file content. ✓

Read-and-report-only invariant — "Never auto-commit, auto-push, kill a daemon" appears verbatim in the body. ✓

Sibling vault-cli:sync-progress reference — correctly namespaced, no fallback logic (same-plugin sibling, guaranteed present). ✓

Resume block — 4-field schema (Next action:, Live background:, Un-pushed / uncommitted:, Open decision:) appears exactly once each; no extra or renamed fields. ✓

Verdict strings — both ✅ Ready to compact and ⚠️ Not compact-safe yet present verbatim. ✓

No closer panel⚪ DONE appears exactly once, inside the prohibition sentence (Do NOT emit a session-close-style closer panel — no ⚪ DONE block). 👤 You: appears zero times. ✓

Namespace contrast/vault-cli:session-close appears fully-namespaced; no bare /session-close found. ✓

Checkpoint path~/.claude/compact-checkpoints/<session-id>.md appears verbatim; per-session (not shared-fixed-path) rationale present. ✓

Path announcement — "state the full path in your final message" present, ensuring the checkpoint file is announced, not silently written. ✓

Graceful degradationdark-factory status || echo "no daemon" and docker ps || echo "no containers" appear as real shell fallback wiring inside the fenced snippet (not just prose). ✓

Daemon interpretation — "A stopped daemon does not mean stopped work" and "A running dark-factory daemon is worth pausing for" both present verbatim. ✓

AC fix verification — The Plan noted that the original AC had an unsatisfiable grep count of 0 for ⚪ DONE (the faithful port necessarily contains the string inside the prohibition sentence). The spec AC at line 52 explicitly documents this: "NOTE: the source file contains ⚪ DONE once, on its line 82, inside the prohibition. An AC demanding 0 is unsatisfiable by a faithful port..." — the spec correctly updated the AC to expect count=1. The command file is therefore correct as-written. ✓

CHANGELOG.md

## Unreleased section added directly above ## v0.112.0, with a properly formatted feat: bullet describing the new command. ✓

specs/in-progress/034-prepare-compact-plugin-command.md and prompts/completed/185-*.md

These are dark-factory internal artifacts. The spec is at status: verifying (its own workflow state); the prompt is status: completed. These files are metadata about the development process, not shipped code.


Step 5: Consolidated Report

Must Fix (Critical): None. ✓

Should Fix (Important): None. ✓

Nice to Have (Optional): None. ✓


Selector Mode Traceability

  • Candidates: 0 judgment rules matched by Step 4b-i glob filter (changed files are markdown/YAML metadata — no source code files)
  • Applicable: 0
  • Skipped: N/A — no candidates triggered
  • Mechanicals: 0 findings across 74 rule YAMLs

Step 6: Next Steps

No test coverage gaps to address — this is a documentation/plugin-command change with no executable code.


Step 7: Manual Review — Complete

Worktree clean. Review done.

{
  "verdict": "approve",
  "summary": "The PR correctly promotes /prepare-compact into the vault-cli plugin as a first-class slash command. The allowed-tools list is granular and capability-scoped (no bare Bash), the session-id trust boundary is correct, the 4-field resume-block schema is preserved, both verdict strings are present, and the CHANGELOG entry is properly formatted. The mechanical funnel found zero findings; the selector-mode adjudication found no applicable judgment rules. The only internal oddity is the spec file at specs/in-progress/ showing status 'verifying' rather than 'completed', but this is a dark-factory workflow state issue, not a PR quality issue.",
  "comments": [],
  "concerns_addressed": [
    "security: allowed-tools uses granular scoping (Bash(git status:*), Bash(pgrep:*), etc.) instead of bare Bash — structurally enforces read-only invariant",
    "correctness: AC for ⚪ DONE count was updated in spec from 0 to 1 to match the faithful port (prohibition sentence contains the string); command file is correct as-written",
    "correctness: dangling step cross-references — verified absent; command file has no broken internal links",
    "tests: this is a plugin command (markdown); no executable test suite applies"
  ]
}

@ben-s-pull-request-reviewer
ben-s-pull-request-reviewer Bot dismissed their stale review August 19, 2026 10:47

superseded by new automated review

@ben-s-pull-request-reviewer ben-s-pull-request-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Now let me do the Step 4c-sel classification. Based on my analysis of the changed files and the rules index:

Changed files: CHANGELOG.md, commands/prepare-compact.md, prompts/completed/185-spec-034-prepare-compact-plugin-command.md, specs/in-progress/034-prepare-compact-plugin-command.md

Step 4b-i candidates (trigger globs matching changed files):

  • changelog/conventional-prefix-required (trigger: CHANGELOG.md) → applicable
  • agent-cmd/command-frontmatter (trigger: commands/**/*.md) → applicable
  • agent-cmd/command-thin (trigger: commands/**/*.md) → applicable
  • changelog/preamble-frozen (script rule, no trigger) → applicable
  • changelog/unreleased-entry-required (script rule, no trigger) → applicable

Step 4c-sel classification:

  • changelog/conventional-prefix-requiredapplicable — CHANGELOG.md changed, feat: prefix present ✓
  • changelog/preamble-frozenapplicable — CHANGELOG.md changed, ## Unreleased at correct position ✓
  • changelog/unreleased-entry-requiredapplicable — CHANGELOG.md has new bullet ✓
  • agent-cmd/command-frontmatterapplicable — new commands/prepare-compact.md created ✓
  • agent-cmd/command-thinapplicable — new commands file, judgment warranted ✓

Step 4d-sel adjudication:

All mechanical findings: 0 (zero findings confirmed)

  1. changelog/conventional-prefix-required — Bullet feat: add /vault-cli:prepare-compact... starts with feat: ✓ PASS
  2. changelog/preamble-frozen## Unreleased at line 11, between preamble (lines 1–9) and ## v0.112.0 (line 15) ✓ PASS
  3. changelog/unreleased-entry-required — New bullet under ## Unreleased ✓ PASS
  4. agent-cmd/command-frontmatter — File has description: and granular allowed-tools: with no bare Bash ✓ PASS
  5. agent-cmd/command-thin — 102-line command with 6 structured steps, bash snippet, and prohibition section — appropriate complexity for its purpose, no judgment violation ✓

Manual verification of plan concerns:

Concern File Verification Status
Granular allowed-tools, no bare Bash commands/prepare-compact.md Lines 8–14: 6 scoped Bash + mkdir, no bare Bash
Session-id from scratchpad path commands/prepare-compact.md:88 "derived from the session's own scratchpad path — never from user input"
Prompt injection surface commands/prepare-compact.md Only Skill/Read/Write/Glob/six scoped Bash; writes only to checkpoint path
All 16 acceptance strings commands/prepare-compact.md All present (verified: sync-progress, Sweep every goal, Compact-safety checks, stopped-daemon warning, RESUME AFTER COMPACT, 4 field labels, compact-checkpoints/.md, Per session, Ready to compact, Not compact-safe yet, Never auto-commit, Unanswered gates, worth pausing for, state the full path, prohibition)
⚪ DONE exactly once commands/prepare-compact.md:102 Line 102: "no ⚪ DONE block" — prohibition sentence only
👤 You: zero times commands/prepare-compact.md Not present anywhere
/vault-cli:session-close namespaced commands/prepare-compact.md:102 "Unlike /vault-cli:session-close" — correctly namespaced
No bare /session-close commands/prepare-compact.md grep '[^:]/session-close' returns 0
CHANGELOG ## Unreleased placement CHANGELOG.md:11 Between preamble and ## v0.112.0
Plugin versions unchanged N/A Diff does not touch .claude-plugin/ files

Selector-mode Traceability:

  • Candidates: 5 rules matched by Step 4b-i glob filter
  • Applicable: 5 rules (all classified applicable; no skipped)
  • Skipped: none

Notes:

  • prompts/completed/ and specs/in-progress/ files have no triggers in rules/index.json and no relevant rule patterns fire on them
  • make precommit was not re-run in this review (selector mode) — CI covers lint+test; the pre-filled context confirmed 0 findings
  • No worktree cleanup needed (was already at PR HEAD)
{
  "verdict": "approve",
  "summary": "Faithful port of `/vault-cli:prepare-compact` as a first-class plugin command. Security surface is tight (6 scoped Bash subcommands + mkdir, no bare Bash, session-id from scratchpad path), all 16 acceptance-criterion strings verified present, ⚪ DONE appears exactly once in prohibition sentence, 👤 You: absent, /vault-cli:session-close correctly namespaced, CHANGELOG ## Unreleased correctly placed with feat: prefix, plugin versions unchanged. No mechanical or judgment violations found.",
  "comments": [],
  "concerns_addressed": [
    "security: granular allowed-tools (6 scoped Bash + mkdir) verified in commands/prepare-compact.md lines 8-14 — no unscoped Bash entry exists",
    "security: session-id trust boundary satisfied by commands/prepare-compact.md:88 — derived from session's scratchpad path, not user input",
    "security: prompt injection surface limited by minimal tool surface (Skill/Read/Write/Glob/six scoped Bash); writes only to checkpoint path",
    "correctness: all 16 load-bearing strings confirmed present in commands/prepare-compact.md",
    "correctness: ⚪ DONE appears exactly once (line 102, prohibition sentence only) — no actual closer panel",
    "correctness: 👤 You: absent (0 occurrences confirmed)",
    "correctness: /vault-cli:session-close correctly namespaced; no bare /session-close",
    "correctness: CHANGELOG ## Unreleased correctly placed between preamble and ## v0.112.0 with feat: prefix",
    "correctness: plugin version strings (.claude-plugin/plugin.json) not in diff — unchanged at 0.112.0",
    "tests: precommit not re-run (selector mode — CI covers lint+test); 0 mechanical findings from ast-grep runner"
  ]
}

@bborbe
bborbe merged commit d4df8ad into master Aug 19, 2026
1 check passed
@bborbe
bborbe deleted the feat/prepare-compact-plugin-command branch August 19, 2026 10:47
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