Frame a new design proposal (RFC-shape) under proposals/ — problem before solution, named beneficiary and observable change, real alternatives, honest drawbacks, and a live open-questions backlog. Read when asked to frame a proposal, write an RFC, propose a design, pitch a change, draft a PRD-style design doc, or open a design proposal for review. Do NOT read to record a decision after it is accepted (use record-a-decision), to write an implementation spec (use write-a-spec), to write a postmortem (use write-a-postmortem), or to review or critique an existing design (use review-a-design).
67
82%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
The platform /open-knowledge skill still governs every markdown operation here (reads via exec/search, writes via write/edit, links as plain relative markdown, never native Read/Edit/Grep/cat on in-scope files). This skill layers proposal-authoring craft on top: it decides what a good proposal contains and in what order you earn each section.
A proposal in proposals/ is a design argument, not a decision and not a plan. It exists to force a choice among options and to give reviewers enough to disagree with. Filename is 0001-feature-name.md — a zero-padded 4-digit sequence plus a kebab title. Status flows draft → fcp → accepted/rejected (fcp = final comment period). Acceptance graduates the proposal to a record in decisions/ — that is a separate, human act and a separate skill.
The failure this skill exists to prevent: an agent jumping to ## Design before anyone agrees what the problem is, padding ## Alternatives with strawmen, and leaving ## Drawbacks empty. Each step below has a gate that blocks that.
Hard gates — do NOT skip ahead. If you are about to draft ## Design and you have not passed the Step 1 framing gate, STOP — you skipped a gate. The whole point of a proposal is that the problem is agreed before the solution is written.
proposals/ and decisions/.proposal template.fcp would require.Create workflow tasks for steps 0–9 in your host's task system if it has one — they make a skipped gate visible mid-session.
Before framing anything, find out what the knowledge base already decided or proposed about this subsystem. A proposal that silently re-litigates an accepted decision is dead on arrival; a proposal that cites it and explains why the decision should be revisited is legitimate.
search({ query: "<subsystem or problem keywords>" }) — semantic, catches synonyms.exec("ls -A proposals/") and exec("ls -A decisions/") — see the sequence space and what has landed.exec("grep -rln <keyword> proposals/ decisions/") — pinpoint files that name the same subsystem.exec("cat proposals/0003-x.md") to read the full doc plus its backlinks.Classify what you find, and carry it into the draft:
| Found | Do this |
|---|---|
| An accepted decision covers this area | The new proposal MUST cite it (a markdown link into decisions/) and, in Motivation, say what changed that reopens it. If nothing changed, tell the user this may not need a proposal at all. |
| A draft/fcp proposal overlaps | Offer to extend or supersede it rather than open a near-duplicate. Two overlapping proposals split the review. |
| Nothing | Proceed clean. |
This is the gate that makes the difference between an RFC and a pile of solution text. Do NOT draft ## Design, and do NOT create the file, until the user confirms the framing.
Produce and return exactly this, then STOP and wait:
## Framing (confirm before I draft)
**Beneficiary:** who is worse off today and will be better off if this ships. A named role or user, not "the system" or "us".
**Observable change:** the concrete, checkable difference they will see. "X drops from N to M", "Y becomes possible", "Z stops happening". Not "improve", not "streamline".
**Forced decision:** the one question this proposal makes reviewers answer. If accepting it doesn't commit anyone to anything, it is a report, not a proposal.
**Rough shape:** one sentence on the direction — enough to know we're framing the right problem, not the design itself.Discipline:
List, don't guess, the sequence. exec("ls -A proposals/"), take the highest existing NNNN, add one, zero-pad to four digits. Guessing collides the moment two proposals are drafted the same week.
Filename: NNNN-kebab-title.md (0007-async-export-pipeline.md). Create it from the template — this is the only way the ## Motivation → ## Design → ## Drawbacks → ## Alternatives → ## Unresolved questions skeleton and the frontmatter arrive correctly:
write({ document: { path: "proposals/0007-async-export-pipeline.md", template: "proposal" } })The template stamps this frontmatter — fill it, don't retype it by hand:
type: proposal
description: "..." # one line: the forced decision, not the feature name
status: draft # stays draft until a human advances it — see Non-goals
authors: [<user>]
created: YYYY-MM-DD
tags: [proposal]Set description to the decision the proposal forces, in one line — it is what a reader sees in a listing.
Fill ## Motivation by edit-ing the created doc. This section has to stand on its own: a reader who disagrees here will never read your Design, and that's correct.
### Non-goals line inside Motivation.Fill ## Design with the actual proposal, pitched at the altitude where a reader could disagree with it. Too low (every function signature) and reviewers rubber-stamp a design they didn't evaluate; too high ("we'll make it faster") and there's nothing to accept. The target: a competent reader could read this section and say "no, I'd do it differently, because…"
[the export boundary decision](./decisions/0004-export-boundary.md).Fill ## Alternatives with at least two real options, each carrying why it was not chosen. Include the honest ones you'd have picked on a different day, plus "do nothing" if it's live.
Structure each:
### Alternative: <name>
What it is — one honest paragraph, argued at its best.
Why not — the specific tradeoff that lost, versus the proposed design.Discipline:
Fill ## Drawbacks with the honest cost of the proposed design — not the alternatives', its own.
Fill ## Unresolved questions as a live backlog, not a disclaimer. Each entry keeps a real open question visible instead of burying it in confident prose.
For each question:
- **<question>** — What would resolve it: <the evidence, experiment, or measurement>. Who decides: <role or person>.fcp period.draft. Hiding uncertainty to look finished is the failure mode; an honest open-questions list is what makes the proposal safe to review.Run before you tell the user it's ready:
[text](./decisions/0004-x.md)), never backticked, never an HTML anchor.links({ kind: "backlinks", ... }) to see what already points where.audit({ path: "proposals/0007-async-export-pipeline.md" }) returns clean (every lint violation + broken internal link) — fix every finding.type: proposal, a one-line description, status: draft, authors, created, tags: [proposal].## Motivation, ## Design, ## Drawbacks, ## Alternatives, ## Unresolved questions. An empty Drawbacks or a strawman Alternatives fails this check even though the section technically exists.status is still draft. You do not advance it — see Non-goals.Close with the user in conversation:
## Recap
- Framed: <beneficiary> gets <observable change>; forces the decision <…>.
- Proposal: proposals/NNNN-title.md (status: draft)
- Alternatives weighed: <n>, chosen over them because <one line>.
- Honest drawbacks: <the main one>.
- Open questions still live: <count> — the fcp agenda.
**To advance to `fcp`:** a human moves status draft → fcp and opens the final comment
period. Acceptance (→ accepted, then a record in decisions/) is a human decision, not
mine. If it's rejected, mark status: rejected and keep the doc — the reasoning is the value.State plainly that advancing status and accepting the proposal are human acts. Your job ended at a well-framed, honestly-argued draft.
decisions/ — that's the sibling /record-a-decision skill, run after a human accepts. This skill stops at draft./write-a-spec.accepted (or fcp) on your own authority. Advancing status is a human act. Leave status: draft; offer the recap of what advancing would require.60997a2
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.