Dogfooding `plan` + `implement` against a throwaway config surfaced one root
defect with many arms: the command templates treat consecutive fenced blocks as
one shell. They are not. Every ```bash fence runs as its own Bash call in its own
process, so a variable set in one block is empty in the next, and `$$` is a
different PID (measured: 21710 vs 22109).
The planner agent confirmed the sharpest arm at runtime, reporting that
`Mode: $RAW_FLAG` "arrived literally unsubstituted" — `--raw` was documented in
three command files while being functionally dead. A machine sweep found the same
root in 20 places across 9 files, well past the two the written fasit predicted:
- `$RAW_FLAG` read from non-shell agent prompts (analyze, plan, implement)
- `$TMPFILE` read across blocks (tokens, manifest, whats-active,
plugin-health) — each command could not read the file it had just written
- `$GLOBAL_FLAG` across blocks (fix)
- `$TODAY` never assigned in any block (campaign), passing
`--reference-date ""` to a write CLI in six places
- three `$$` temp paths handed to the Read tool (fix), which expands neither
All now follow the hardened drift.md pattern: a fixed literal path, or a
re-derivation inside each block that needs it.
Also fixed, all confirmed against ground truth rather than inferred:
- `implement` printed a rollback ID it never captured (the timestamp lived only
inside a command substitution) — the one message a user reads after a bad run
- `plan` reported "No analysis results found" for valid sessions, because Read
was pointed at a glob it cannot expand; now uses Glob and verifies the
analysis report exists before spawning the agent
- five phase commands wrote state.yaml with two of four required fields; since
the agent writes all four, a follow-up write silently deleted the rest
- `implement` promised rollback deletes created files; rollback deliberately
leaves them (M-BUG-26 still open) — the doc, not the engine, was wrong
- `implement` claimed a score delta with no pre-change measurement
- `verifier-agent` was told to write a report it has no tool to write
- dead `Task` tool name in always-loaded rule context; planner-agent template
demonstrated the inline file content its own line 110 forbids
The sweeps land as tests/commands/command-shell-state-shape.test.mjs, verified
red before the fix and proven able to fail by reintroducing the defect. Two
existing tests asserted the old bash-block mechanism rather than the intent and
were updated. Suite 1449/0; frozen v5.0.0 snapshots and all scanner code
untouched.
Not fixed, deliberately: neither command scope-gates its actions to the audit
target. The generated plan included an edit to a real file under ~/.claude,
outside the throwaway target, because the skill/agent scanners are machine-wide.
That is a design change, not a side fix.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0195udHgCcFegzm7ecKku2Yc
112 lines
4.7 KiB
Markdown
112 lines
4.7 KiB
Markdown
---
|
|
name: config-audit:plan
|
|
description: Phase 4 - Generate prioritized action plan with risk assessment
|
|
allowed-tools: Read, Write, Glob, Grep, Agent, Bash
|
|
model: opus
|
|
---
|
|
|
|
# Config-Audit: Plan Generation (Phase 4)
|
|
|
|
Generate a prioritized action plan based on analysis results.
|
|
|
|
## Prerequisites
|
|
|
|
- Must have completed Phase 2 (analysis)
|
|
- Phase 3 (interview) is optional — plan works with or without it
|
|
|
|
## Arguments
|
|
|
|
- `$ARGUMENTS` may contain `--raw` to forward to the planner-agent's instructions; in `--raw` mode the agent renders v5.0.0 verbatim severity prefiks instead of humanized `userActionLanguage` urgency phrasing.
|
|
|
|
## Implementation
|
|
|
|
### Step 1: Verify session state
|
|
|
|
Find the most recent session with analysis completed using the **Glob tool** on `~/.claude/config-audit/sessions/*/state.yaml`, then Read the newest match. The Read tool takes one literal path and does not expand `*` — pointing it at the glob makes this step report "no analysis results" even when a valid session exists.
|
|
|
|
If no session is found: "No analysis results found. Run `/config-audit` first to scan your configuration."
|
|
|
|
Then confirm the report itself exists — a session can carry a valid `state.yaml` and still be missing its report. Read `~/.claude/config-audit/sessions/{session-id}/analysis-report.md`. If it is absent: "Session {session-id} has no analysis report. Run `/config-audit analyze` to generate it." Stop — the planner agent has nothing to read.
|
|
|
|
### Step 2: Tell the user what's happening
|
|
|
|
```
|
|
## Creating Action Plan
|
|
|
|
Building a prioritized plan based on your analysis results...
|
|
Actions are ordered by impact, with risk assessment and dependency tracking.
|
|
```
|
|
|
|
### Step 3: Parse flags and spawn planner agent
|
|
|
|
Check whether `$ARGUMENTS` contains `--raw`. Carry the answer yourself: the agent
|
|
prompt below is **not** a shell, so a variable assigned in a bash block cannot be
|
|
referenced from it. Substitute `{mode}` literally with `--raw` or with `humanized`
|
|
when writing the prompt.
|
|
|
|
Tell the user: **"Generating your action plan (this takes about 30 seconds)..."**
|
|
|
|
```
|
|
Agent(subagent_type: "config-audit:planner-agent")
|
|
model: opus
|
|
prompt: |
|
|
Generate action plan based on:
|
|
- Analysis: ~/.claude/config-audit/sessions/{session-id}/analysis-report.md
|
|
- Interview: ~/.claude/config-audit/sessions/{session-id}/interview.md (if exists)
|
|
Mode: {mode} ("humanized" = humanized; "--raw" = v5.0.0 verbatim severity prefiks)
|
|
Create a prioritized plan that consumes the humanized finding fields:
|
|
- Group actions by userImpactCategory (e.g., "Configuration mistake",
|
|
"Conflict", "Wasted tokens", "Missed opportunity", "Dead config")
|
|
- Lead each action with userActionLanguage ("Fix this now," "Fix soon,"
|
|
"Fix when convenient," "Optional cleanup," "FYI") rather than raw
|
|
severity. The humanizer already replaced jargon-heavy
|
|
title/description/recommendation strings with plain-language
|
|
equivalents — render them verbatim, do not paraphrase.
|
|
- Surface relevanceContext when it isn't "affects-everyone" so the
|
|
user knows whether a fix touches shared config or just their machine
|
|
- Include risk assessment per action (low/medium/high)
|
|
- Rollback strategy
|
|
- Dependency ordering
|
|
- Effort estimates
|
|
Output to: ~/.claude/config-audit/sessions/{session-id}/action-plan.md
|
|
```
|
|
|
|
### Step 4: Present the plan summary
|
|
|
|
Read the generated plan and show a concise overview:
|
|
|
|
```markdown
|
|
### Action Plan Ready
|
|
|
|
**{N} actions** organized by priority:
|
|
|
|
| # | Action | Risk | Effort |
|
|
|---|--------|------|--------|
|
|
| 1 | {title} | {low/med/high} | {quick/moderate/involved} |
|
|
| 2 | ... | ... | ... |
|
|
| ... | ... | ... | ... |
|
|
|
|
Full plan: `~/.claude/config-audit/sessions/{session-id}/action-plan.md`
|
|
|
|
You can edit the plan file to remove, reorder, or modify actions before implementing.
|
|
|
|
### What's next
|
|
|
|
- **`/config-audit implement`** — Execute the plan with automatic backup and verification
|
|
- **`/config-audit interview`** — Set preferences first to customize the plan (optional)
|
|
```
|
|
|
|
### Step 5: Update state
|
|
|
|
Update `state.yaml` with all four fields `.claude/rules/state-management.md` requires — a partial write drops the fields that make an interrupted run resumable:
|
|
|
|
- `current_phase: "plan"`
|
|
- `completed_phases`: append `plan` to the existing array (read it first; never overwrite it with a fresh list)
|
|
- `next_phase: "implement"`
|
|
- `updated_at`: current timestamp
|
|
|
|
The planner agent may already have written these. Read the file before writing and preserve whichever fields it set — a full-file Write that names only two fields silently deletes the other two.
|
|
|
|
## Plan Modification
|
|
|
|
Users can edit `action-plan.md` before implementation — remove unwanted actions, adjust priority, or add custom actions. The implementer parses the modified plan.
|