name: proposal-act description: 'Accept, defer, dismiss, or resolve a proposal. For accepted proposals, asks how to proceed: start implementing now, create a session task, or note for manual implementation. Activates on messages like "accept PROP-", "dismiss PROP-", "defer PROP-", "resolve PROP-".'
Proposal Act
Take action on a proposal: accept, defer, dismiss, or resolve.
Usage
/claude-code-hermit:proposal-act accept PROP-019
/claude-code-hermit:proposal-act defer PROP-015
/claude-code-hermit:proposal-act dismiss PROP-012
/claude-code-hermit:proposal-act resolve PROP-008
If no action or ID is provided, ask the operator which proposal and action.
Resolving a Proposal ID
Before reading any proposal file, resolve the operator's input to a filename using this algorithm:
- Trim whitespace and uppercase the input.
- Match against
/^PROP-(\d+)(?:-(.+))?$/. If no match: error "Not a PROP id." - Zero-pad the integer to 3 digits (e.g.
PROP-6→PROP-006). - Build the glob pattern. Always anchor: never use bare
PROP-NNN*.md(collides with 4-digit NNN files likePROP-0061.mdonce proposal counts cross 1000).- If no suffix (e.g.
PROP-006): glob two anchored patterns and union the results:PROP-006.md(legacy exact match) plusPROP-006-*.md(new-format files with that integer). - If suffix present (e.g.
PROP-006-103612orPROP-006-capability-brainstorm-103612): globPROP-006-*<suffix>*.md. The leading-*brackets the slug for timestamp-only inputs; the trailing wildcard catches thea/b/… collision-suffix variant. The disambiguation prompt resolves any over-matches.
- If no suffix (e.g.
- Glob
.claude-code-hermit/proposals/<pattern>(or each pattern in turn for the two-pattern no-suffix case, then union). - Count the matches:
- 0 matches: error "No proposal matches [input]. Use /proposal-list to see available proposals."
- 1 match: proceed with that file.
- 2+ matches: show a disambiguation prompt:
Re-resolve with the operator's reply.Multiple proposals match PROP-NNN: PROP-NNN-capability-brainstorm-103612 — [title of first match] PROP-NNN-session-cost-tracking-104207 — [title of second match] Reply with the full ID to continue.
Timestamp Convention
All timestamps in frontmatter and Operator Decision text use ISO 8601 with timezone offset (e.g., 2026-04-06T14:30:00+01:00). Use the timezone from config.json if set, otherwise UTC.
Accept Flow
When the operator accepts a proposal:
- Resolve the proposal file using the resolution algorithm above, then read it.
- Update the YAML frontmatter: set
statustoaccepted, addaccepted_dateas timestamp. Do NOT setresolved_date— resolution happens when reflect confirms the pattern is gone. If the file uses old bullet-point metadata (- **Status:**), update that instead. 2b. First-response tracking: Check if the proposal'srespondedfield is alreadytrue. Iffalse: setresponded: truein frontmatter, then append arespondedevent:
Then callbun ${CLAUDE_PLUGIN_ROOT}/scripts/append-metrics.ts .claude-code-hermit/state/proposal-metrics.jsonl '{"ts":"<now ISO>","type":"responded","proposal_id":"PROP-NNN","action":"accept"}'bun ${CLAUDE_PLUGIN_ROOT}/scripts/generate-summary.ts .claude-code-hermit/state/. Ifrespondedis alreadytrue, skip the append (prevents double-counting). - Append a timestamp to the Operator Decision section:
Accepted on 2026-04-06T14:30:00+01:00.
3a. Session tracking: Read state/runtime.json for session_id and session_state (both are used below). If session_id is non-null, set accepted_in_session to that session ID in the proposal's YAML frontmatter. If no session is active (session_id is null), leave accepted_in_session: null.
3b. Routine proposals. If the proposal metadata contains Type: routine and a ## Config section with a JSON block:
- Parse the JSON block. Validate: must have id, schedule, skill, enabled fields.
- Check for duplicate id in existing config.json routines array — if found, update the existing entry instead of appending.
- If no duplicate found, append the routine entry to config.json routines array.
- Respond: "Routine '{id}' added to config. Run /claude-code-hermit:hermit-routines load to register it immediately."
- Notify the operator.
- Skip step 4 — no further implementation needed.
3c. Success signal (optional). Check whether the proposal body has a ## Success Signal section with a non-empty predicate line (ignore comment lines starting with <!--).
- If a non-empty predicate line is found, validate it:
bun ${CLAUDE_PLUGIN_ROOT}/scripts/eval-success-signal.ts --validate "<predicate line>" - Exit 0 → set
success_signal: <predicate line>in the proposal's YAML frontmatter. - Exit non-zero → log a one-line warning to SHELL.md Findings:
PROP-NNN success_signal ignored: <reason printed by the script>. Leavesuccess_signal: null. - No
## Success Signalsection, or the section is empty / comment-only → leavesuccess_signal: null. - Never block accept regardless of outcome.
Ask: "How should this be implemented?"
"Start implementing now" (default, typical answer): run the falsification gate, then handle session lifecycle, then execute in this turn. Falsification gate (runs first, before any session transition). Verify the proposal is actionable as written with a read-only pass. Skip only when the body contains
## Skill Improvementand/skill-creator:skill-creatoris in the available-skills list (step (e) routes that to/skill-creator:skill-creator) — if## Skill Improvementis present but skill-creator is absent, the proposal becomes a code-edit implementation, so the gate runs to produce aPROCEEDfile list for the dispatch. Also skip if the body contains## Skill Draft— authoring is delegated to/skill-creator:skill-creatoron accept, not a code-edit plan — but first check that thesource_artifactpath listed in## Skill Draftexists and is readable (if the file is missing or unreadable, REJECT with codestale-paths— the procedure brief was removed or archived; the operator should re-run reflect to generate a fresh brief).Agent selection — check the harness's available-skills list (never
claude plugin listor disk checks):feature-dev:feature-devin available-skills → usefeature-dev:code-exploreras the subagent.feature-dev:feature-devabsent → fall back to the nativePlanagent. Read only the returned text; ignore any file it writes under~/.claude/plans/.- If the agent errors → log a one-line warning to SHELL.md Findings and continue to the session-lifecycle branch. Never block.
Invoke with the proposal's
## Contextand## Proposed Solutionsections plus this fixed instruction:"You are a read-only falsification gate. Verify every cited path and symbol against the current code. Return line 1 as exactly:
REJECT: <already-done | partially-done | stale-paths | nonexistent-symbols | too-vague> — <one-line evidence>orPROCEED(+ complete file list to modify). If REJECT, give file:line evidence. Do not produce a build plan for a rejected proposal. Do not write any files."Append the returned line-1 verdict to the proposal's
## Operator Decisionsection as provenance, then branch:PROCEED→ continue to the session-lifecycle branch below (step (a)). Use the agent's complete file list over any files mentioned in the proposal body.REJECT(stop before any session transition —session_stateand SHELL.mdTask:stay untouched):- Interactive mode → surface to the operator: "Falsification gate: [verdict] — [evidence]. Proceed anyway? Y to override / N to re-scope the proposal first." Y → continue to the session-lifecycle branch below (step (a)). N → stop; status stays
accepted. Operator re-scopes and re-runs/proposal-act accept PROP-NNN. - Autonomous mode → do not implement; notify via channel: "PROP-NNN: falsification check — [evidence]. Reply 'override PROP-NNN' to implement anyway."
a. Use the
session_statealready read fromstate/runtime.jsonin step 3a to branch. b. Idle: delegate toclaude-code-hermit:session-mgrto transition toin_progressand fill SHELL.md Task as "Implement PROP-NNN:". Proceed to (e). c. In progress: confirm before switching: "Currently working on: . Switch to PROP-NNN? Y/N".
- Interactive mode → surface to the operator: "Falsification gate: [verdict] — [evidence]. Proceed anyway? Y to override / N to re-scope the proposal first." Y → continue to the session-lifecycle branch below (step (a)). N → stop; status stays
- Yes: append
[HH:MM] switched to PROP-NNN: <title> (prior task: <prior task>)to SHELL.md## Progress Log; overwrite SHELL.mdTask:field with "Implement PROP-NNN:"; runtime.json session_statestaysin_progress. Proceed to (e). - No: fall back to "Create a session task" below.
d. Waiting: fall back to "Create a session task" without asking, then notify: "PROP-NNN queued. Session is currently waiting."
e. Implement the proposal. If the body contains
## Skill Improvementandskill-creator:skill-creatoris in the available-skills list, use/skill-creator:skill-creatorfor the implementation (in-main; continues to e.5). Before invoking skill-creator, parse thesource_artifact:line from the## Skill Improvementbody; if it is present and the path is readable (searchcompiled/thencompiled/.archive/), read the brief and pass its content as input context to skill-creator improve — this anchors the improvement to the skill's original spec. Missing or unreadable anchor: proceed without it (no REJECT — an improve proposal is still actionable without the brief, unlike## Skill Draftwhich hard-rejects stale paths). If the body contains## Skill Draft, follow the procedure-capture install flow below (in-main; continues to e.5). Otherwise, dispatch the full implementation tail to the nativegeneral-purposeagent (this includes## Skill Improvementproposals when skill-creator is absent):
Dispatch (falsification gate returned PROCEED, no in-main skill handler): Invoke
general-purposevia the Agent tool with this prompt (fill in the bracketed value). The subagent inheritsCLAUDE.md/CLAUDE.local.md, can invoke skills, and can spawn nested subagents — so it runs the whole tail (implement → quality gate → verification) in its own isolated context and returns one report.Implement the accepted proposal at
<absolute path to PROP-NNN-*.md>, then run its quality gate and verification. Work entirely in this context; your final message is the only thing returned to the caller.- Read the proposal file. The
## Operator Decisionsection contains aPROCEEDline from the falsification gate with the authoritative file list — use that list as your scope (over any files mentioned in the proposal body). - Do the edits and any test/fix loops yourself. You may spawn a nested Explore subagent if the proposal warrants a search.
- Quality gate. Read
.claude-code-hermit/config.json→quality_gate.tier(treat missing/invalid asbudget).budget→ skip cleanup.quality→ invoke/claude-code-hermit:simplifyfocused on the files you touched.balanced→ delegate to theclaude-code-hermit:quality-gate-judgesubagent (pass the proposal path + touched files); onRUN:invoke/claude-code-hermit:simplifyas forquality, onSKIP:skip. Capture/simplify's totals line (applied N · deduped M · principle-rejected K · …). Best-effort: if the judge or/simplifyerrors, note it and continue — never block on this step. - Verification. Read the proposal's
## Verificationsection. If it has real steps (more than the HTML-comment placeholder), perform them. If a step fails, attempt one fix and re-verify; if it still fails, setVerification: failedwith the output and stop (do not loop further). If the section is empty or placeholder-only, setVerification: none defined. - You cannot prompt the operator — if you hit an ambiguous spec or an undecidable/destructive choice at any step, stop and return an escalation block rather than guessing.
Return exactly this structure as your final message (nothing else):
Status: implemented | escalated | blocked: <reason> Touched files: <relative paths, space-separated | none> Tests run: <commands + pass/fail summary | none> Quality gate: <tier> — simplify <totals line> | skipped: <reason> | n/a Verification: passed | failed: <output> | none defined Deferred for operator: <none | what was ambiguous and the safe no-op you took>After the subagent returns (the dispatched path ran its own quality gate + verification, so it skips main's e.5/e.6 and is handled here):
Status: implementedandVerification:ispassedornone defined→ run/proposal-act resolve PROP-NNN, then notify the operator (interactive) or channel (autonomous), building the message from theQuality gatefield: if it carries a simplify totals line → "PROP-NNN implemented and resolved. /simplify applied N edits (M deduped, K rejected on principle)." (use "… /simplify made no changes." when N == 0, and "… /simplify completed (totals unavailable)." if the line is unparseable); if it isskipped:orn/a→ "PROP-NNN implemented and resolved."Verification: failed: <output>→ do not resolve. Surface the failure output to the operator (interactive) or channel (autonomous). Proposal status staysaccepted.Status: escalatedorStatus: blocked: <reason>→ do not resolve. Surface theDeferred for operatorblock to the operator (interactive) or channel (autonomous). Proposal status staysaccepted.
If the body is vague and the falsification gate did not return
PROCEED, ask the operator for clarification before proceeding.Procedure-capture install flow (when body contains
## Skill Draft):- Parse
name,source_artifact,install_target, andtriggersfrom the## Skill Draftblock. - Collision guard: if
install_target(.claude/skills/<name>/SKILL.md) already exists, do not overwrite. Ask the operator: "Skill<name>already exists at<install_target>. Overwrite / Rename / Cancel?" Default = Cancel. - Invoke
/skill-creator:skill-creatorusingsource_artifact(the procedure brief incompiled/) as input. Pass the proposednameandtriggersso it can author the correct frontmatter and trigger phrases./skill-creator:skill-creatoroutputs a proposed SKILL.md. - Second confirmation gate: present the full authored SKILL.md to the operator and require an explicit yes/no before installing. An installed skill auto-loads into every future session, so the operator approves the artifact, not just the intent. Record the operator's verdict (confirmed / declined) in the PROP's
## Operator Decisionsection.- Confirmed: proceed to install.
- Declined: stop. Notify the operator that they can re-run
/proposal-act accept PROP-NNNafter revising the procedure brief.
- Create
.claude/skills/<name>/and write the authored SKILL.md there. The procedure brief incompiled/stays as the permanent audit trail — do not move or delete it. - Do not auto-stage or commit the new skill file. Notify the operator: "Skill
<name>installed at<install_target>. Commit it if you want it tracked in version control."
Verification for procedure-capture proposals (e.6 note): the
## Verificationsection of a procedure-capture PROP should instruct reading the installed file's frontmatter (name/descriptionparse) rather than checking the live available-skills list — the harness only picks up new skills on the next session reload, so the live list is unreliable here. A missing or malformed installed file blocks resolution per the normal e.6 contract. e.5. Quality gate (tier-branched). Applies to in-main implementations only (the## Skill Improvement→ skill-creator and## Skill Draft→ procedure-capture branches). Dispatched implementations run their own quality gate inside the subagent (see the step (e) dispatch) and are resolved there. Read.claude-code-hermit/config.json→quality_gate.tier. Resolve per this table:| Config state | Resolved tier | |---|---| | `tier` is `"budget"` / `"balanced"` / `"quality"` | use as-is | | `tier` missing, `quality_gate` missing, or value not in enum | `budget` (log one-line warning to SHELL.md Findings) | Build a touched-files list from the writes made during the in-main implementation (skill-creator / skill-draft). This is the precise scope for `/claude-code-hermit:simplify` and for the judge. If you can't reliably enumerate it (multi-turn work), omit it; downstream falls back to `git diff --name-only HEAD`. Branch on the resolved tier: - **`budget`**: skip `/claude-code-hermit:simplify` entirely. Proceed to (f). Resolution notification stays plain: "PROP-NNN implemented and resolved." - **`quality`**: invoke `/claude-code-hermit:simplify` directly. Pass the touched-files list as focus when enumerable, otherwise invoke with no focus (it falls back to the working-tree diff): ``` /claude-code-hermit:simplify focus on PROP-NNN implementation: path/a, path/b ``` The skill runs three parallel reviewers (reuse, quality, efficiency), applies the edits it picks itself, and ends with a totals line: `applied N · deduped M · principle-rejected K · stale-anchor skips L · parse failures P`. Capture that line and pass through. Resolution notification: "PROP-NNN implemented and resolved. /simplify applied N edits (M deduped, K rejected on principle)." When `N == 0`: "PROP-NNN implemented and resolved. /simplify made no changes." If the totals line is missing or unparseable, fall back to "PROP-NNN implemented and resolved. /simplify completed (totals unavailable)." — never block resolution. - **`balanced`**: delegate to `claude-code-hermit:quality-gate-judge` with: ``` Proposal: <absolute path to PROP-NNN-*.md> Touched-Files: <space-separated relative paths> (omit this line if not reliably enumerable) ``` Parse line-1 verdict: - `RUN: <reason>` → invoke `/claude-code-hermit:simplify` per the `quality` tier above. Notification: "PROP-NNN implemented and resolved. Judge: <reason>. /simplify applied N edits (M deduped, K rejected on principle)." When `N == 0` use "… /simplify made no changes." Same totals-missing fallback as the `quality` tier. - `SKIP: <reason>` → skip `/claude-code-hermit:simplify`. Notification: "PROP-NNN implemented and resolved. Judge skipped /simplify: <reason>." **The quality gate is cleanup, not correctness** — `/simplify` does not check that the proposal works. Correctness is verified by the `## Verification` gate in step (e.6); proposals with no defined verification still resolve, but the skip is recorded. Best-effort throughout: if any step errors out (judge fails, `/simplify` failed or totals unavailable, file read fails), log a one-line warning to SHELL.md Findings and fall back to skip. The gate never blocks resolution.e.6. Verification gate (in-main implementations only — dispatched implementations verify inside the subagent). Read the proposal's
## Verificationsection. - If it contains real steps (more than the HTML-comment placeholder), perform them now — after the quality gate has applied any/simplifyedits — before resolving. If a defined step fails, do not resolve: report the failure to the operator (or channel in autonomous mode) and stop. - If the section is empty, missing, or contains only its placeholder comment, appendVerification: none defined for PROP-NNN — skipped.to SHELL.md## Findingsand proceed. The omission is recorded, not blocked.Unlike the e.5 quality gate (best-effort, never blocks), e.6 **blocks resolution when a defined verification step fails** — that is the correctness check the quality gate does not provide.f. (in-main path) When verifiably done: run
/proposal-act resolve PROP-NNN, then notify the operator (or channel in autonomous mode) with the tier-appropriate message from (e.5). (Dispatched implementations resolve + notify in the step (e) post-return handling.)"Create a session task" → Write
.claude-code-hermit/sessions/NEXT-TASK.md:# Next Task (from PROP-NNN) ## Task [One-line task derived from the proposal's Proposed Solution] ## Context [Summary of the pattern/problem from the proposal, including Related Sessions] ## Suggested Plan 1. [Step derived from Proposed Solution] 2. [Step derived from Proposed Solution] 3. Verify the fix resolves the patternIf
NEXT-TASK.mdalready exists: do not write. Status still flips toaccepted(operator intent is recorded). Notify: "PROP-NNN accepted. NEXT-TASK is already pending another proposal. Run/session-startto consume it first, then re-run/proposal-act accept PROP-NNNand pick 'Start implementing now' or manual." Otherwise write the file. Then append any of the following bullets to the end of the Suggested Plan, in order, numbered sequentially from4.(quality-gate bullet is last so/claude-code-hermit:simplifyreviews any skill-creator output):- (if the proposal contains
## Skill ImprovementAND/skill-creator:skill-creatoris available)Use /skill-creator:skill-creator to build and validate the skill. - (if the proposal contains
## Skill Draft)Use /skill-creator:skill-creator to author the captured procedure from the source_artifact (see ## Skill Draft), present the final SKILL.md to the operator for confirmation, then install it to the install_target only on confirmation. - (if
quality_gate.tierin.claude-code-hermit/config.jsonis not"budget"— i.e."balanced"or"quality")Run /claude-code-hermit:simplify on the touched files for a cleanup pass, then commit.Confirm: "Task prepared. The next/session-startwill offer this as the default task."
- (if the proposal contains
"I'll handle it manually" → Just mark accepted. Respond: "Marked as accepted. No further action taken."
Notify the operator: "PROP-NNN accepted: [title]"
Note: There is no "Update OPERATOR.md" path. OPERATOR.md is operator-owned — the agent reads it but does not modify it. If the operator wants to update OPERATOR.md based on a proposal, they do it themselves.
Defer Flow
- Resolve the proposal file using the resolution algorithm above, then read it.
- Update the YAML frontmatter: set
statustodeferred, adddeferred_dateas timestamp. Do NOT setresolved_date— deferral is not a terminal state. If the file uses old bullet-point metadata (- **Status:**), update that instead. 2b. First-response tracking: Same as accept flow — checkrespondedfield, set totrueiffalse, appendrespondedevent with"action":"defer", callgenerate-summary.ts. Skip if alreadytrue. - Ask: "Any note on why it's deferred or when to revisit?" (optional — operator can skip)
- If a note is provided, append to the Operator Decision section:
Deferred on 2026-04-06T14:30:00+01:00. Reason: [operator's note] - Respond: "PROP-NNN deferred."
Deferred proposals still appear in /proposal-list but are sorted below open proposals.
Dismiss Flow
- Resolve the proposal file using the resolution algorithm above, then read it.
- Update the YAML frontmatter: set
statustodismissed, adddismissed_dateandresolved_dateas timestamps. If the file uses old bullet-point metadata (- **Status:**), update that instead. 2b. First-response tracking: Same as accept flow — checkrespondedfield, set totrueiffalse, appendrespondedevent with"action":"dismiss", callgenerate-summary.ts. Skip if alreadytrue. - Ask: "Reason for dismissal?" (optional — operator can skip)
- If a reason is provided, append to the Operator Decision section:
Dismissed on 2026-04-06T14:30:00+01:00. Reason: [operator's reason]
4b. Dismissal learning — only when a reason was provided in step 3. Judge whether the reason states a durable preference, rule, or taste that applies to a family of future proposals (e.g. "don't propose process changes for things I do twice a year", "stop suggesting test-coverage proposals on docs-only changes") versus a one-off or proposal-specific response ("not now", "already did this manually", "the analysis is wrong", "duplicate of last week"). If generalizable, issue the standard "remember it" reflection framed as a feedback-type entry: state the preference as a rule, add a brief Why: and How to apply: so proposal-triage and reflection-judge can match it in their memory cross-check. Apply auto-memory discipline: respect WHAT_NOT_TO_SAVE (no file paths, no debugging recipes, no facts derivable from grep), keep it concise. The native auto-memory flow writes feedback_<slug>.md and updates the MEMORY.md index — do not write those files directly. If the reason is one-off or sub-threshold, skip — save nothing.
5. Respond: "PROP-NNN dismissed." If step 4b saved a preference, add: "Remembered that as a standing preference (future similar proposals may be filtered)."
Dismissed proposals are hidden from the default /proposal-list view. Use "show all" with /proposal-list to see them.
Resolve Flow
Used when reflect has surfaced a sparse-cadence proposal as a resolution candidate (pattern absent from recent sessions but cadence too infrequent to auto-resolve). Also available directly: /claude-code-hermit:proposal-act resolve PROP-NNN.
- Resolve the proposal file using the resolution algorithm above, then read it.
- Update the YAML frontmatter: set
statustoresolved,resolved_dateto current timestamp. Do NOT setdismissed_date. If the file uses old bullet-point metadata (- **Status:**), update that instead. - Append a
resolvedevent to proposal-metrics.jsonl:bun ${CLAUDE_PLUGIN_ROOT}/scripts/append-metrics.ts .claude-code-hermit/state/proposal-metrics.jsonl '{"ts":"<now ISO>","type":"resolved","proposal_id":"PROP-NNN"}' - Append to the Operator Decision section:
If the resolve was triggered by reflect's auto-resolve flow (pattern absent from recent sessions), the caller may append "Pattern confirmed absent." but this is no longer the default — resolve also covers implementation completion via the Start-now branch.Resolved on 2026-04-06T14:30:00+01:00. - Respond: "PROP-NNN resolved."
No first-response tracking on resolve — the proposal was already accepted and that event was already logged.