Agent skill
change-proposal
Present proposed code changes visually before implementing. Use when the user says "show me options", "compare approaches", "what should we do", or when multiple approaches exist, changes span multiple files, or architecture decisions need before/after comparison.
Install this agent skill to your Project
npx add-skill https://github.com/EpicenterHQ/epicenter/tree/main/.agents/skills/change-proposal
SKILL.md
Change Proposal
When proposing non-trivial changes, make your reasoning visible before acting. The user should see what will change, why, and what alternatives were considered—before a single file is edited.
Follow writing-voice for prose sections.
When to Use This
- Multiple valid approaches exist (show competing options)
- Changes span 3+ files (show the dependency graph)
- Architecture or ownership shifts (show before/after diagrams)
- Lifecycle or data flow changes (show the flow)
- The user asks "what do you think?" or "how should we do this?"
For trivial changes (typo fix, single-line edit, obvious bug), skip this and just do it.
The Three Tools
1. Before/After Diffs
Show what specific code will change. Use fenced diff blocks with file paths.
--- a/workspace.ts
+++ b/workspace.svelte.ts
@@ createWorkspaceState()
- let client = buildWorkspaceClient();
+ let client = $state(buildWorkspaceClient());
return {
get current() { return client; },
- async reset() {
- await client.clearLocalData();
- await client.dispose();
- client = buildWorkspaceClient();
+ async reset(options?: { key?: Uint8Array }) {
+ await client.dispose();
+ client = buildWorkspaceClient(options);
},
};
Rules:
- Show the smallest meaningful diff, not the whole file
- Include enough context lines (3–5) to understand placement
- Group related changes together, separate unrelated ones
- Label each diff with the file path and function/scope
2. ASCII Architecture Diagrams
Show how components relate before and after the change. Use the characters from progress-summary: ┌ ┐ └ ┘ ─ │ ├ ┤ ┬ ┴ ┼ ▼ ▲ ──→ ←──
Before:
auth ──signOut()──→ workspace.reset() ──→ internally rebuilds
│ (self-manages lifecycle)
├── clearLocalData()
├── dispose()
└── client = build()
After:
auth ──signOut()──→ workspace.current.dispose()
setWorkspaceClient(build())
│
workspace is a reactive slot ← auth owns lifecycle
When to use which diagram type:
- Ownership diagrams: Who controls what (arrows show control flow)
- Layer diagrams: Stacked boxes for architectural layers
- Flow diagrams: Data or control moving between components
- Journey diagrams: Evolution from attempt A → B → C
3. Comparison Tables
When multiple approaches exist, present them as a table with clear trade-off dimensions.
A: Self-managed B: Slot + builder C: Auth owns state
─────────────── ───────────────── ──────────────────
Who holds $state? workspace workspace auth
Who decides wipe? workspace auth (explicit) auth (explicit)
Circular deps? same as today same as today WORSE
God module risk? workspace neither auth
Rules:
- Rows are dimensions the user cares about
- Columns are approaches
- Use short phrases, not sentences
- State your recommendation after the table, not inside it
Proposal Structure
For non-trivial changes, present in this order:
- One sentence: What you're proposing and why
- Diagram: Architecture before/after (or competing approaches side-by-side)
- Diffs: Concrete code changes for the recommended approach (hardest file first)
- Trade-offs: What you gain, what you lose, what stays the same
- Ask: "Should I proceed with [recommendation], or prefer [alternative]?"
Scaling by Complexity
| Change scope | What to show |
|---|---|
| 1 file | Just the diff, no diagram |
| 2–5 files | Diff of the hardest file + one diagram showing relationships |
| 5+ files | Full proposal: comparison table, diagrams, diffs for hardest 2–3 files |
| Architecture decision | Comparison table mandatory, even if only 2 options |
| Competing approaches | All three tools: diagram per approach, diff per approach, comparison table |
Good vs Bad Proposals
Good
workspace.tscurrently self-manages its lifecycle. I'd split it: workspace becomes a reactive slot + builder, auth owns the lifecycle decisions.writes reads auth ──────────────────► workspace.svelte.ts ◄──── consumers builds, sets let client = $state() .current decides wipe set(newClient) via $effectdiff--- a/workspace.ts (createWorkspaceState) +++ b/workspace.svelte.ts - let client = buildWorkspaceClient(); + let client = $state(buildWorkspaceClient());Trade-off: auth gains 10 lines of explicit lifecycle code, workspace loses its god-object methods. Net simpler because lifecycle decisions are visible at the call site.
Should I proceed with this, or keep workspace self-managed?
Bad
I'll refactor workspace.ts to use a slot pattern and move lifecycle management to auth.svelte.ts. This involves changing how the client is created and disposed, updating the state management to use $state, and modifying the reset function to accept an optional key parameter. The consumers will use $effect to automatically rebind when the workspace changes.
The bad version describes changes in prose. The good version shows them.
What to Avoid
- Prose-only proposals: If you can draw it, draw it. If you can diff it, diff it.
- Showing every file: Show the hardest 2–3. Mention the rest as "same pattern."
- Burying the recommendation: Lead with your pick, then show alternatives.
- Fake precision: Don't show a diff for code you haven't read yet. Read first, then diff.
Didn't find tool you were looking for?