← the whole session plugin/skills/resolve-proposals/SKILL.md
Fix approved proposals and close the loop — claim, fix, commit with Resolves-Proposal tags, mark completed. Use when the person asks you to fix or implement approved proposals, or says a proposal has been addressed.
Resolve Proposals
This skill ensures every proposal fix creates a traceable commit-to-proposal link. Without this, proposals rot in the queue even after the code is fixed.
The Full Loop
Proposal created → Approved → Claimed → Code fixed → Committed with tag → Status set to completed
↑ YOU ARE HERE
Where Proposals Live
Follow /proposal-schema for the format. By default (nothing else set up), proposals are markdown files with frontmatter in the folder printed by alignment-harness records proposals — one file per proposal, {ID}-{slug}.md. All the steps below describe that default path.
If this project has its own database-backed proposals API (optional, advanced infrastructure this skill doesn't require), the same claim/fix/commit/mark-completed operations apply, just as HTTP calls with a key instead of file reads. Wherever a step below says "update the file," an API-backed setup does the equivalent write through its own endpoint instead. Set it up once via /alignment-harness:harness-setup and note the endpoint shape there — don't assume one exists.
Step 1: Claim Each Proposal
Before starting work, claim so other agents don't duplicate effort.
Local file (default): add to the proposal's frontmatter:
claimed_by: <your agent identifier>
claimed_at: <ISO timestamp>
If an API is configured:
curl -s -X POST "$PROPOSALS_API/<PROPOSAL_ID>/claim" \
-H "X-API-Key: $PROPOSALS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"agentId": "<your agent identifier>"}'
Step 2: Read Code Before Changing It
MANDATORY: Read every file you will modify. Never assume what code does. The proposal may describe a problem that was already fixed — if so, skip to Step 5 (mark completed without code changes).
Check the proposal's Files section (or targetFiles field, if present) for which files to read.
Step 3: Make the Fix
Follow this project's own coding standards (its CLAUDE.md, or /code-principles-how-to-code if this plugin's copy is installed). A few defensive habits worth calling out explicitly for proposal fixes, general to any codebase:
- NEVER leave catch blocks empty
- NEVER send a response without returning immediately after (whatever your framework's equivalent of
res.json()withoutreturnis) - NEVER bare-destructure a context/hook that could be null
- Code defensively: fail-OPEN by default when the failure mode would otherwise deny a paying/authorized user access
- NEVER name variables with bare ambiguous words — qualify with domain context
Step 4: Commit with Resolves-Proposal Tags (CRITICAL)
This is the step that closes the loop. The Resolves-Proposal: trailer is what a post-commit hook (if you have one) parses to auto-mark proposals as completed — and even without a hook, it's what makes git log --grep a reliable way to find which commit resolved which proposal.
Commit per repo (don't cross repos in one commit):
cd <repo>
git add <only-your-changed-files>
git commit -m "$(cat <<'EOF'
fix(scope): <what the user now experiences differently>
<1-2 sentence description of what changed and why>
Resolves-Proposal: <full-proposal-id>
Resolves-Proposal: <full-proposal-id-2>
Tags: <relevant tags>, Priority:<x>/10
Files: <changed files>
EOF
)"
Rules:
- One
Resolves-Proposal:line per proposal id (whatever id format this project's proposals use — see/proposal-schema) - Group proposals into single-responsibility commits — one commit per concern, not one per proposal
- If two proposals touch the same file for the same reason, one commit resolves both
- Do NOT push — only commit locally, the person decides when to push
Example (illustrative — replace with your own project's proposal ids and files)
git commit -m "$(cat <<'EOF'
fix(errors): users now see error feedback when a background job fails instead of a frozen UI
Previously, catch blocks in the job-status helper silently swallowed errors —
users saw a frozen UI with no feedback. Now shows an error message via the
existing error-banner component in all failure paths.
Resolves-Proposal: LP-041
Resolves-Proposal: LP-044
Tags: user-facing, error-handling, Priority:9/10
Files: src/helpers/JobStatusHelper.js
EOF
)"
Step 5: Mark Completed
Local file (default): update the proposal file's frontmatter and add a ## Resolution section at the bottom:
status: completed
resolved_date: YYYY-MM-DD
resolution_commit: <commit hash from Step 4>
## Resolution
- **Status**: Completed
- **Date**: YYYY-MM-DD
- **Commit**: {commit hash}
- **What changed**: {one sentence — the UX-level fix}
If an API is configured (and no post-commit hook already does this automatically):
COMMIT_HASH=$(git rev-parse HEAD)
curl -s -X POST "$PROPOSALS_API/<PROPOSAL_ID>/completed" \
-H "X-API-Key: $PROPOSALS_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"agentId\": \"<your agent identifier>\", \"commitHash\": \"$COMMIT_HASH\"}"
Step 6: Report What Happened
Print a summary table:
| Proposal | Status | Commit |
|----------|--------|--------|
| LP-041 - job-status helper swallows errors | FIXED | abc1234 |
| LP-044 - feature gate fails open when it shouldn't | ALREADY RESOLVED | skipped |
Include "ALREADY RESOLVED" for proposals where the code was already fixed — this is valuable signal that the proposal queue has drift.
Step 7: Propagate Resolution to Other Surfaces, If Any Exist
The proposal file itself (Step 5) is the source of truth by default. If this project ALSO keeps proposals visible somewhere else, update that copy too so it doesn't silently disagree with the file:
- If this proposal has a linked pipeline run directory (for example, a
REPORT.mdunder a runs folder), update that file's own status frontmatter the same way as Step 5, and append the same## Resolutionsection to it. - If this project tracks pipeline runs in a separate index file (a
tracking.jsonor similar), update that run's entry with the same status and commit. - If the person uses an Obsidian vault or similar for review, and the proposal file lives there, opening it after the update is a nice touch so they see the new status without having to go looking:
(Only do this if the person has confirmed they use Obsidian for this — don't assume it.)open "obsidian://open?vault=<vault-name>/<path-to-file>"
If none of these extra surfaces exist for this project, Step 5 alone is the whole loop — don't invent surfaces to update.
When a Proposal is Already Resolved
If you read the code and the problem described in the proposal is already fixed:
- Do NOT make any code changes
- Still mark the proposal as completed (Step 5) — this closes it in the queue
- Still propagate the resolution (Step 7) if this project has the extra surfaces described there
- Note "ALREADY RESOLVED" in your summary
- This is expected — code evolves faster than the proposal queue
Anti-Patterns
- NEVER skip the commit tag — "I'll add it later" means it never happens
- NEVER commit without reading the code first — proposals go stale, you'll commit a fix for a non-problem
- NEVER bundle unrelated proposals into one commit — defeats single-responsibility and makes revert impossible
- NEVER push — only commit locally, the person decides when to push
- NEVER change a proposal's status to
approved/rejected/deferredyourself — per/proposal-schema, only the person does that. This skill only ever moves a proposal fromapprovedtocompleted, because that's the part that follows directly from your own fix.
Known Limitations
- If this project has no database-backed proposals API, "claiming" is advisory only (a frontmatter field other agents are expected to check), not an enforced lock. That's an acceptable tradeoff for the default, file-based setup — it only really matters when multiple agents work the same queue concurrently.
- Intent DB entries are not automatically resolved — if the proposal links to Intent DB items, resolving those is a separate manual step (use
/intent-db). - A frozen record of a session (a compaction) can't be edited after creation, if this project uses those — resolution context for a pipeline-linked proposal is better carried in the run's own
REPORT.md## Resolutionsection (Step 7) than assumed to update anything frozen.