-
Notifications
You must be signed in to change notification settings - Fork 2
Design Decisions
Why FeatherSpec is shaped the way it is. Every rule here has a cost attached to breaking it.
No rule and no workflow is written down twice — apart from three reinforcements listed below, which are deliberate and documented.
-
AGENTS.mdis the only place mutable state lives —DocLanguage, thearchitecture:snapshot, and Style & Output Preferences. Every command that changes those writes toAGENTS.md.CLAUDE.mdis one line and holds no copy. -
Rules and workflow bodies are single files both tools read. No
.github/instructions/, no.github/copilot-instructions.md— they would only duplicate what.claude/rules/and.claude/commands/already provide. The one Copilot-side folder that does exist,.github/prompts/, holds loaders: a link and a sentence, never a rule. -
AGENTS.mdstates policy; rule files state craft.AGENTS.mddefines the spec and plan lifecycle and the Memory Bank file set..claude/rules/specs.md,plans.mdandmemory-bank.mdcover only how to write those files, and link toAGENTS.mdfor the policy..specs/README.mdis orientation and links rather than a restatement.
This is not tidiness for its own sake. Two copies of a rule drift, and when they drift the model follows whichever it read last. One copy cannot drift.
All three exist for the same reason: a path-scoped rule loads only when a matching file is read, which is too late for a workflow that is creating or moving that very file.
| Reinforcement | Where | Why |
|---|---|---|
Spec essentials (DocLanguage, the **Status:** line, the document structure) |
commands/sdd-specify.md |
a brand-new spec has not been read, so .claude/rules/specs.md may not have loaded yet |
Plan essentials (DocLanguage, naming, the **Status:** line, the file structure) |
commands/sdd-plan.md |
same reason — a brand-new plan file has not been read, so .claude/rules/plans.md may not have loaded yet |
| Lifecycle safety rules (one folder at a time, delete the original, duplicate check, plan travels with spec) | commands/sdd-lifecycle.md |
this workflow performs the moves and deletions; the safety rules must be in front of the model as it acts |
In all three cases AGENTS.md remains authoritative: if a copy ever diverges, fix the copy.
Do not "clean up" these by deleting them — each one is load-order insurance, and removing it
reintroduces a real failure mode.
A skill advertises itself: both tools read every skill's name and description up front so
the model can decide to load it. Claude Code drops that advertising when a skill sets
disable-model-invocation: true, but VS Code does not document the same guarantee — so eight
workflow descriptions could sit in the system prompt of every single request.
Workflows here are commands, which no model is offered:
-
.claude/commands/<name>.mdholds the body and Claude Code runs it as/<name> -
.github/prompts/<name>.prompt.mdis a one-line loader that points Copilot at that same body
Reach for a skill only when a workflow genuinely needs the model to trigger it on its own. These do not: they create, move and delete files, and they should run when you say so.
Because one body file is executed by both tools, it is written to the lowest common denominator. Each constraint has a reason:
-
No
!`shell`injection. Copilot does not support it; it would land in the prompt as literal text. Bodies instruct the model to run a command and use the result instead. -
No
$ARGUMENTS/$0/$1. Same reason — Copilot's documented mechanism is${input:…}. Bodies say "the user may name a spec path after the command; if none is given, list the candidates and ask." Both tools append the user's trailing text to the invocation, so the model still sees it. -
No tool names in the bodies. The tool that fetches a web page is
WebFetchin one and#fetchin the other, so bodies name the capability ("your web search or fetch capability") and state what to do when it is missing. Same for terminal work: bodies say which command to run and use the result, rather than assuming a tool name. -
The file name is the command name in both tools, so
.claude/commands/sdd-plan.mdand.github/prompts/sdd-plan.prompt.mdmust share the stem.
A comment at the top of each body restates this, so nobody reintroduces the syntax later.
A plan that lives only in the chat is gone when the session ends. Making the plan a file changes three things:
-
Resumability — a new session reads
Current stepandSession handoffand continues, instead of asking you to re-explain. - Reviewability — the plan shows up in a pull request next to the code it produced.
- Impact analysis — the traceability table can be read in reverse, so a changed requirement yields the list of steps and code paths it reaches before anything is edited.
The rule that makes all three work: the plan is updated in the same change set as the code. The assistant's own todo list is scratch state that dies with the session; the plan file is the durable one, and when the two differ, the file wins and gets corrected.
.specs/ and .memory-bank/ are your project's content, not tool configuration. The predecessor
template kept them under .github/, which made them look like GitHub plumbing and tied them to
one vendor's folder. At the top level they are visibly data, they are tool-neutral, and they
survive any decision you later make about which assistant to keep.
Two reasons: the commands do not shadow Claude Code's built-in commands, and typing /sdd shows
you the whole workflow set in one autocomplete group.
Start here
Reference
Design & interop
- Interop Matrix
- Design Decisions
- Specify Method
- Committing to One Tool
- Migrating from the predecessor
- Releasing
Help