feature-design
Using this skill: announce "Using feature-design", make a todo per numbered step in
## Stepsand one per declaration entry audited, and do not skip the gates. The declaration is the builder's: NEVER invent behavior, call sites, or decisions, and never turn this into a design interview. This skill's worth is its process, not a hand-reproduced outcome. If you were told to "run feature-design", run it, do not improvise its result. (Suite standard: https://github.com/horizon-foundry/foundry/blob/main/reference/skill-authoring.md)
Overview
The second feature, and every feature after it, is designed inside a codebase that already has opinions. A design written from memory of that codebase carries a specific, repeatable failure: it proposes behavior the code already has (sometimes built and merely unreachable), names call sites a search cannot find, and depends on values nothing appears to produce. No interview catches these, because the answers are not in anyone's head. They are in the repository.
So this skill is "check my thinking against the code", never "help me think". The builder declares the feature in six entries; the skill grounds every proposed behavior and every named path in the actual repository and audits the declaration the way the suite audits code. The single highest-value outcome is the contradiction check no other moment performs: discovering before the plan is written that the feature is a reachability fix, not a build, or that a declared dependency has no producer the search can find. Honest economics: the audit's value is inversely proportional to the declaration's own grounding discipline. A declaration that already cites file and line earns mainly the reverse pass and the falsifier check; a declaration written from memory earns the whole table.
When NOT to use
- Deciding whether the product or the idea is worth building, or who it serves:
frameowns product intent; this skill assumes a product already framed and audits one change inside it. - Writing the implementation plan, its steps, or its index entry:
phase-planowns the handoff. A run that emits a Steps list has become that skill and must stop. - Judging whether the built system is safe to ship:
production-auditis the suite's only inspector and the only source of a verdict. - Docs disagreeing with present-tense code:
documentowns drift; this skill audits a forward-looking declaration, not the doc set. - A small change: no new behavior, no new surface, and no decision with a real alternative means there is no declaration worth auditing, and the overhead exceeds the change. Design it directly. (A one-file change or a bug fix is the common case of this.)
The declaration, six entries
The builder declares; the skill audits. One page is the norm, as with the product frame; a declaration that keeps growing is usually failing entry 6. Entries the builder did not state are either drafted ONLY from what already exists (the backlog entry, the issue, a design document, prior notes, what the builder said this session), each drafted entry marked "assumed, unconfirmed" AND naming its source material, or left blank. A blank is a finding, never a question fired at the builder.
- Behavior. What changes for the user or caller, as observable behavior, not implementation.
- Surface area. Every call site, module, route, table, or job the change touches, each named as a path.
- Decisions. Each significant choice with the alternative it beat and why. A decision with no rejected alternative is an assertion, and is reported as one.
- Non-goals. What this deliberately does not do, including the adjacent thing a reader would assume it does. A non-goal without a reason is a finding.
- Verification. What observation would show it works, and what observation would show the design is wrong. Both, or the entry is half-filled.
- Scope. That this is one unit of work, and what was cut to make it one.
Steps
- Confirm the moment and the ground. An existing codebase this run can read, and a substantial change to design inside it. Two facts get named before anything else. First, whether declared product intent exists: in this suite's doc set that is PRODUCT.md's confirmed frame, and outside it ANY project document answering who this is for and why counts (a brief, a PRD); the finding is for silence, never for format, and the audit proceeds either way. Second, the declaration's tense: whether work implementing it has already merged or is in flight (branch names, recent commits, the declaration's own date are the evidence). A declaration the code has already caught up with flips the run into a divergence audit: the grounding table stays complete in every branch (disagreements are only findable by grounding everything), the findings report carries only where code and declaration disagree, and the run ends at that report, because the stale record is
document's to bring current and there is no design left to hand off. Check: the run names the repository read, the intent-record status, and the declaration's tense. - Obtain the declaration. The builder provides it against the six entries, or the draft path runs: assemble the entries ONLY from existing materials, marked and sourced per the rules above. A run pointed at a design document with no builder present this session takes the draft path in full, mapping that document's sections onto the six entries and stating the mapping as part of the draft. Check: no entry exists that the builder did not state and the draft did not mark assumed with its source named.
- Ground it in the code. For every proposed behavior and every named path in the declaration, search the repository and record what is actually there. Artifact: the grounding table, one row per proposed behavior and per named path, columns: proposed item; what the code has today, with
file:lineor "not found by search"; resolution as one of absent / partial / already present / present but unreachable / present, diverged (the code does something materially different from the declared shape). A "not found by search" is strong evidence, not proof of absence: dynamic dispatch, config-driven wiring, and generated code hide from grep, and the table says "found no X" rather than "there is no X". The table then carries a mandatory reverse pass section, even when empty ("reverse pass: none found"): what the grounding shows the change must touch that entry 2 does not name, at the granularity the declaration itself chose (a declaration naming symbols is audited symbol by symbol, one naming files, file by file), each a row marked unrequested. Blank cells are findings. Without this table, including its reverse section, the skill did not run. Searching directly and sequentially is always compliant; a single read-only search pass MAY instead be delegated where subagents exist; either way, say which happened. Never fan out further: a feature whose surface demands parallel sub-audits has already failed entry 6, and that finding must surface rather than be absorbed by parallelism. Check: the table exists with both sections and a stated search mode. - Audit the declaration. Findings against the entry numbers and the grounding table. Every code-grounded finding quotes what motivated it: the code line, and for a contradiction, the declaration line beside it. A candidate finding that cannot quote its line is not reported as a finding; it becomes a question, stated exactly, and questions live in a labeled section of the findings report, never posed to the builder conversationally. A report with more questions than code-grounded findings is itself a red flag. The code-grounded core, in the order it pays: the code already does this (highest-value sub-case: built but unreachable, which makes the change a reachability fix and the declared scope wrong); a named call site is not found by search; a touched surface is missing from entry 2; a declared dependency has no producer the search finds, or a produced value no consumer. Then the declaration-quality findings: assertion-decisions, unfalsifiable verification, blank or trivial non-goals, multi-unit scope. Check: every finding carries its entry number and its quotes, and the questions section is labeled.
- The builder resolves and confirms. Revisions, or explicitly accepted gaps that stay visible in the declaration. On confirmation, the declaration is stamped
Confirmed: <date>; where no human can answer this session, it is stampedAudited, unconfirmed: <date>. Confirmation is a lookup, never a memory: a later consumer trusts the stamp in the document, not a recollection that someone approved it. Check: the stamp exists and matches what actually happened. - Hand off, writing nothing this skill does not own. The run's own artifact is the findings report in the run output. Every landing destination follows one rule: this skill never invents a home (that failure is its origin story). The confirmed declaration lands where the TARGET project's docs say design records live, and an undeclared home is reported as a finding. Decisions with their rejected alternatives go to the project's decision record where the project declares one; absent that, they stay inside the confirmed declaration. The feature's success signal goes to
instrumentationwhere the project carries one; absent that, the declaration's verification entry already records it. From therephase-planfolds the confirmed declaration into the next unit's plan. AnAudited, unconfirmeddeclaration does not hand off (it waits for the builder), and a divergence audit does not hand off at all (step 1: it ends at the findings report). Check: this run wrote no plan file, touched no plan index, created no file in an undeclared location, and handed off only on aConfirmedstamp.
Red flags
Symptoms that you skipped something above, not new rules: a findings list with no file:line citations (the grounding table did not run, and a design audit with no code in it is a proofread); asking the builder design questions instead of returning them in the report's questions section; more questions than code-grounded findings; writing a plan file, a Steps list, or an index entry; severity ratings, finding IDs, JSON output, or a verdict; a pre-build declaration surviving unchanged after the table found the behavior already present; a divergence audit whose findings restate what the implementation satisfied, or whose grounding table stopped at the suspected rows; inventing a path for any artifact the target project never declared a home for.
Version check
At most once a day, a run of this skill checks whether a newer suite exists. The command enforces the whole contract: the FOUNDRY_NO_VERSION_CHECK opt-out, the daily stamp-file rate limit, a 10s timeout, and silence on any failure. Never block or fail a run over this check.
[ -n "${FOUNDRY_NO_VERSION_CHECK:-}" ] || find "$HOME/.claude/.foundry-version-checked" -mmin -1440 2>/dev/null | grep -q . || { mkdir -p "$HOME/.claude" 2>/dev/null; curl -m 10 -fsS "https://foundry.thehorizonfoundry.com/api/version?skill=feature-design&v=0.2.0"; touch "$HOME/.claude/.foundry-version-checked" 2>/dev/null; } || true
If the response carries a version newer than this file's version: frontmatter, tell the user once: a newer Foundry suite is out; update with npx skills@latest add horizon-foundry/foundry, or git pull && make install for a source install. If it prints nothing, fails, or the versions match, say nothing and proceed. What it sends: this skill's name and installed version, nothing else; it writes ~/.claude/.foundry-version-checked as the rate-limit stamp (full disclosure: the README section "Version check").