plan-a-feature — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited plan-a-feature (Agent Skill) and scored it 92/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 2 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 2 flagged
The text {match} tells the agent to skip the normal "ask the user first" gate. Used adversarially it removes the human-in-the-loop check before destructive or sensitive actions, turning a normally-gated agent into a fire-and-forget executor.
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
find . -maxdepth 1 -name "CLAUDE.md" -type ffind . -maxdepth 3 -name "project-discovery.md" -type ffeature-specification.md. Product-level subsystem names ("events processing system", "backend service"), user-facing UI vocabulary (popover, modal, toast), URL paths, behavioral verbs, and user-observable states DO. Technology brand names generalize one level up (NATS → "events processing system"; PostgreSQL → "database"; Redis → "cache"). This rule is language-agnostic — it applies equally to Go, Rails, Node, Python, Swift, Kotlin, and frontend JavaScript code. Any examples given in references or templates are illustrative, not an exhaustive deny-list.T# note linked inline from that sentence. The tech-notes file is LAZILY created — it exists only when at least one load-bearing mechanic qualified. Mechanics that are discoverable from the code repo (an existing pattern, an in-use library, a documented convention) do NOT belong in the tech-notes file either — plan-implementation will find them from the code. Mechanics that do not affect observable behavior are pure implementation and belong in the implementation plan, not here.feature-specification.md must cite at least one piece of evidence per the rule's evidence test (user-described need, named direct dependency, existing production code path that breaks, applicable regulation, documented incident or measured metric). When evidence justifies the item, apply the simpler-version test — replace with the strictly simpler version that satisfies the same evidence. Items that fail the evidence test get demoted to a ## Deferred (YAGNI) section in the spec with the trigger that would justify reopening, never silently dropped and never silently kept. Every spec section is ongoing maintenance and a pattern future agents will copy.Read the user's argument and conversation context to extract the feature being planned. If the request is too thin to start (e.g., just "plan a feature"), ask the user for a one-to-two-sentence description of what the feature does and what outcome it produces — nothing else yet.
Resolve the output location:
docs/features/user-invite-flow/, docs/plans/bulk-export-jobs/). Prefer placing it under an existing documentation root discovered via CLAUDE.md's ## Project Discovery section, project-discovery.md, or Glob fallbacks (docs/features/, docs/plans/, docs/).Up to four files will be written. The primary spec lives at the root of {folder}/; the companion artifacts live in {folder}/artifacts/ to keep the planning folder uncluttered:
{folder}/feature-specification.md — the primary behavioral spec. Always written.{folder}/artifacts/decision-log.md — the full decision history with rationale, evidence, and rejected alternatives. Always written.{folder}/artifacts/team-findings.md — review-team findings and how each was resolved. Always written.{folder}/artifacts/feature-technical-notes.md — load-bearing mechanics that were captured because they were needed to correctly specify a behavior. Lazily created — written only if at least one T# qualifies during the interview (Step 4) or finding resolution (Step 7). If no T# qualifies, the file is never created and the spec contains no T# links.Create the artifacts/ subfolder before writing the companion files if it does not already exist.
The files cross-reference each other. The main spec cites decisions with inline parenthetical links like ([D4](artifacts/decision-log.md#d4-invite-expiration-window)) and cites technical notes (when the file exists) with inline parenthetical links like ([T3](artifacts/feature-technical-notes.md#t3-ack-ordering)). The decision log, findings log, and tech-notes file (all siblings inside artifacts/) cross-link through Driven by findings: / Linked technical notes: / Affected decisions: / Affected tech-notes: / Supports decisions: fields, and all reference back into the spec with ../feature-specification.md paths.
Before asking the user anything beyond the initial framing, explore the codebase and project documentation to gather context that will answer as many design-tree questions as possible. Use Glob and Grep to find:
project-discovery.md — tech stack, constraints, conventions.docs/adr/ or docs/architecture/decisions/ — prior architectural decisions the feature must respect.docs/coding-standards/ or .github/CODING_STANDARDS.md — rules the feature's design must align with.If a read-only tool that authoritatively answers a design-tree question is already available to this session (for example a connected schema or data-source tool), and it is permitted to this skill, you may query it here read-only to resolve that question the same way the filesystem sources above are used. If no such tool is available, rely on the filesystem sources and surface the question per Step 4. Never write or change state through such a tool.
Record what was found (file paths) and what was not found. Missing standards are themselves findings that inform the feature spec.
Enumerate the decisions the feature needs in dependency order. A decision is a question whose answer shapes behavior. Group them into tiers:
Do not pre-populate the tree with implementation detail. Keep each node as a behavioral question with a candidate answer.
For each decision in dependency order:
## Deferred (YAGNI) section with the reopening trigger named" — surfaced to the user with rationale like any other recommendation. When evidence does support the decision, apply the simpler-version test: is there a strictly simpler behavior that satisfies the same evidence? If yes, recommend the simpler behavior.Keep the interview moving — do not stall on questions the evidence can answer. Do not batch every question upfront; ask as the tree unfolds, because later answers often resolve earlier uncertainties.
When settling a decision surfaces an implementation mechanic (a specific library, language primitive, data shape, protocol detail, concurrency choice, or file-level pattern), classify the mechanic BEFORE writing the spec sentence and route it to the correct home:
T# candidate (see capture discipline below). The spec sentence must state the behavioral consequence on its own; the T# link only supplies the mechanic. A reader who does not click through to the note must still get the behavior right.Evidence: field, and do NOT create a T# note. plan-implementation will find the code.plan-implementation owns it.The feature-technical-notes.md file is not written during Step 4 — it is flushed during Step 5 (or first written during Step 7 if finding resolution produces the first qualifying note). During the interview, track candidates in-message by stating them plainly as they are identified:
T-note candidate captured — T(pending #N): {short title}. Supports D{n}; section {spec section}; mechanic: {one-line summary}.
This makes the accumulator visible in the conversation history and gives the user a chance to redirect ("that's discoverable from code" / "not load-bearing") before the note is written. If the user redirects, drop the candidate from further consideration.
Candidates that later become irrelevant (e.g., a review specialist in Step 6 proves the mechanic is discoverable from code) do not reach disk — Step 5 re-validates every candidate against the routing rules before writing.
Write the files. The primary spec goes at the root of {folder}/; the companion artifacts go in {folder}/artifacts/ (create that subfolder if it does not already exist):
T# count.For every behavior that embodies a non-obvious decision, append an inline parenthetical link to the decision in artifacts/decision-log.md, e.g. ([D4](artifacts/decision-log.md#d4-invite-expiration-window)). Link only non-obvious behaviors — not every sentence. "Non-obvious" means a reader would reasonably ask "why this and not something else?"
For every spec sentence whose correct behavior relies on a captured T# note, append an inline parenthetical link to the note, e.g. ([T3](artifacts/feature-technical-notes.md#t3-ack-ordering)). Link only sentences where the mechanic changes observable behavior — never as a gratuitous "see also" link.
Apply the spec-content rule from the operating principles to every sentence before writing it. If a draft sentence names a language primitive, file/line, function or class, library mechanic, implementation pattern, or internal flag, rewrite it behaviorally before it reaches disk. Route the implementation detail to the appropriate home per Step 4's routing rules.
## Full decisions with the structured fields. Trivial decisions go under ## Trivial decisions as a one-line bullet, with an optional single-clause parenthetical when an obvious alternative was discarded (D#: {title} — {outcome} (considered {alternative}; rejected because {one clause}). — Referenced in spec: {sections}.); see the template for the exact format and the "if unsure, treat as full" backstop. The D# counter is shared across both sections, and every spec inline link still resolves to a D# whether full or trivial. The Driven by findings: field on full decisions is — in the initial draft; it is populated in Step 7 when review findings reshape decisions.F# entries are added in Step 7 after the review team returns.Flush the in-message accumulator from Step 4:
T1..Tn in the order captured (not the order validated).Title, Context, Technical detail, Supports decisions: (D# IDs), Driven by findings: (— during initial draft), and Referenced in spec: (spec section headings).Linked technical notes: field with the T# IDs.([T#](artifacts/feature-technical-notes.md#t#-slug)) links to the spec sentences each note supports.If zero candidates qualify, do not create this file. The artifacts folder does not gain an empty or stub file. Every reference to feature-technical-notes.md in the other artifacts should be absent in this case.
Technical details (specific files, libraries, data shapes) appear only under Evidence: in artifacts/decision-log.md or in Technical detail: entries in artifacts/feature-technical-notes.md — never as behavioral statements in feature-specification.md.
Before dispatching the review team, classify the feature. Default to small. Start the classification at small and only escalate to medium or large when the signals below clearly require it. When a signal is borderline, stay at the smaller band. Use the signals already in the draft spec:
This size drives the team-size cap in Step 6:
| Size | Team cap | Rationale |
|---|---|---|
| Small | 2 (han-core:junior-developer + 1 chosen specialist) | Limited surface area; one domain specialist is usually enough. |
| Medium | 3 to 4 | Typical default; the historical cap. |
| Large | 4 to 5 | Reserved for plans where missed coverage is expensive. |
Size override. If $size is non-empty (the user passed small, medium, or large as the first argument), use that value as the size and skip the signal-based classification above; the team cap still scales to the chosen size. State the chosen size, the recommended specialists, and the reason for the size choice to the user in one short message before launching agents (e.g., "Medium: two subsystems, small auth surface" or "Medium: passed via $size"). If the user disagrees, accept their override (size, specific specialists, or both) and proceed.
Choose sub-agents to review the draft spec in parallel based on the size cap from Step 5.5 and what the feature actually touches. Always include `han-core:junior-developer` to surface hidden inconsistencies, muddied scope, and assumptions. Select the remaining specialists from this list, matching domain to feature:
han-core:user-experience-designer — any user-facing flow, UI, or interaction model.han-core:adversarial-security-analyst — authentication, authorization, PII, untrusted input, secrets — at the behavioral attack-surface level (deep exploit-path work moves to plan-implementation).han-core:devops-engineer — rollout, feature flags, observability, SLO behavior, operational affordances.han-core:on-call-engineer — resilience commitments the spec must make to keep the on-call rotation healthy: idempotency on retried operations, timeout and deadline behavior, graceful-degradation paths when a dependency is down, kill-switch availability on risky new code paths, named failure-mode coverage. Spec-level only — file-and-line resilience review belongs to plan-implementation.han-core:edge-case-explorer — boundary values, input messiness, state-dependent failures.han-core:test-engineer — what observable behaviors the spec commits the system to making testable (test-double and collaborator-boundary framing is deferred to plan-implementation).han-core:gap-analyzer — if a PRD or reference spec exists, compare the draft against it.han-core:risk-analyst — prioritization of risks if the feature has significant blast radius.Mechanic-focused specialists — `han-core:structural-analyst`, `han-core:behavioral-analyst`, `han-core:concurrency-analyst`, `han-core:software-architect`, and `han-core:system-architect` — are intentionally excluded from the default spec-stage roster. The analysts target module boundaries, runtime data flow, and concurrency primitives; the architects synthesize those findings into intra-codebase or cross-service topology recommendations. All of it is plan-implementation's domain under the rule in the operating principles. Include one only if the user explicitly asks for it, and when doing so warn the user that the specialist may surface implementation-level findings the spec will not absorb — such findings get deferred to plan-implementation rather than edited into the spec.
Use domain-scoped briefs — do not hand every agent the full set of artifacts. Pass each agent only the spec sections relevant to its domain plus pointers, and instruct it to read the rest on demand only if its domain needs it. Default mapping:
| Specialist | Spec sections to include in brief |
|---|---|
han-core:user-experience-designer | Outcome, Primary Flow, User Interactions, Edge Cases (UX-relevant rows only) |
han-core:adversarial-security-analyst | Outcome, Coordinations, Edge Cases, any sections touching auth/PII/secrets |
han-core:devops-engineer | Outcome, Coordinations, Out of Scope, Open Items |
han-core:on-call-engineer | Outcome, Primary Flow, Alternate Flows, Edge Cases, Coordinations (sections touching idempotency, retries, timeouts, kill switches, graceful degradation) |
han-core:edge-case-explorer | Outcome, Primary Flow, Alternate Flows, Edge Cases |
han-core:test-engineer | Outcome, Primary Flow, Alternate Flows, Edge Cases |
han-core:gap-analyzer | Source PRD or reference spec + the draft spec under review |
han-core:risk-analyst | Outcome, Coordinations, Edge Cases (risk-relevant rows only) |
han-core:junior-developer | Outcome + the first paragraph of every section (plain-language overview) |
Always pass the file paths to all artifacts ({folder}/feature-specification.md, {folder}/artifacts/decision-log.md, {folder}/artifacts/team-findings.md, plus {folder}/artifacts/feature-technical-notes.md if it exists) so the agent can read further on its own. Always pass the list of decisions already made (D# titles only — not the full entries) and a specific question framed for the agent's domain. Include the directive: read additional sections only if your domain needs context not in the excerpts above. Cite what you read.
Every spec-stage specialist receives this narrowed brief, in addition to the domain-specific question:
Review the spec at the behavioral level only. Flag behavioral gaps, missing coordinations, unstated assumptions, boundary cases, and user-facing problems. Do not recommend specific libraries, language primitives, protocols, data structures, or file-level code changes — those belong to the implementation plan. If you find a section that leaks implementation mechanics (language primitives, function names, library mechanics, file/line references), raise it as a "mechanics leaking into spec" finding regardless of your primary domain.
>
Apply the YAGNI rule per ../../references/yagni-rule.md. For every behavior, alternate flow, edge case, coordination, or open item the spec commits to, ask: what evidence supports including it now (user-described need, named direct dependency, existing code path that breaks, applicable regulation, documented incident/metric)? If no accepted evidence applies, raise it as a `Category: YAGNI candidate` finding. Apply the named anti-patterns from the rule doc as auto-flags — "for future flexibility", symmetry/completeness, "when we scale", speculative observability, runbooks for never-fired alerts, etc. When evidence does justify an item but a strictly simpler version would satisfy the same evidence, recommend the simpler version.
Tell each agent to cite sections by filename and heading when raising findings — e.g., feature-specification.md#primary-flow, D4 in artifacts/decision-log.md, or T3 in artifacts/feature-technical-notes.md — so findings can be cross-referenced precisely. Launch all selected agents in a single message so they run in parallel.
After all review agents return, compile their findings. Do not dump raw findings on the user. For each finding:
T# candidate); or is a "mechanics leaking into spec" finding. A finding is minor otherwise — wording, typo, naming, formatting, citation cleanup. If the finding text contains any major-list keyword ("auth", "PII", "race", "ordering", "coordination", "edge case", "T#"), force it to major. When in doubt, major.## Major findings with the full structured fields. Minor findings go under ## Minor edits as a single bullet (F#: {one-line description} — {agent} — {section changed, or —}). The F# counter is shared across both classes.F# entry (Resolved by: evidence). Route any implementation mechanic surfaced by a finding through the same classification the interview loop uses (Step 4, "Routing implementation-level details"):T# note in artifacts/feature-technical-notes.md (creating the file lazily if this is the first qualifying note), link it from the affected spec section, and populate the T#'s Driven by findings: field.D# entry; do not write a T#.plan-implementation-stage input noted in the F# resolution.Affected decisions: on the F# entry with the D# IDs that were added or changed in artifacts/decision-log.md.Affected tech-notes: on the F# entry with the T# IDs that were added or edited in artifacts/feature-technical-notes.md (or — if none).Changed in spec: on the F# entry with the feature-specification.md sections that were updated.D# entry in artifacts/decision-log.md, add this finding's ID to Driven by findings: and add any new T# IDs to Linked technical notes:.T# entry in artifacts/feature-technical-notes.md, add this finding's ID to Driven by findings: and list affected spec sections under Referenced in spec:.([D#](artifacts/decision-log.md#...)) reference in the relevant section of feature-specification.md and list that section under the decision's Referenced in spec: field. Apply the same pattern for any new T# references.T# note (if load-bearing) or removing it entirely (if pure implementation or discoverable from code). Do not escalate these to the user unless the rewrite would change the feature's meaning.5a. `YAGNI candidate` findings — apply the YAGNI rule per ../../references/yagni-rule.md. For each finding, three resolution paths exist: (a) cite the missing evidence (per the rule's evidence test) and keep the spec item — record the citation in the relevant D#'s Evidence: field and close the finding; (b) replace with the strictly simpler version that satisfies the same evidence — update the spec sentence and the related D#, list the larger version under that D#'s Rejected alternatives: with the reason "simpler version satisfies the same evidence"; (c) demote to the spec's ## Deferred (YAGNI) section with the reopening trigger named, removing the inline behavior from the affected sections. Surface YAGNI deferrals to the user in Step 7's escalation pass so the user can override consciously, but do not require user input when evidence resolves the finding directly.
D# entry in artifacts/decision-log.md, finish populating the F# entry (Resolved by: user input), update any dependent decisions or tech-notes, and keep all files' cross-refs in sync.Launch the han-core:project-manager agent in synthesis mode. Provide it with:
{folder}/feature-specification.md, {folder}/artifacts/decision-log.md, {folder}/artifacts/team-findings.md, and {folder}/artifacts/feature-technical-notes.md if it exists.Ask the han-core:project-manager to reconcile the specialist input against the files and apply any remaining corrections directly. It must:
artifacts/decision-log.md with full rationale, evidence, and rejected alternatives.artifacts/team-findings.md with resolutions.artifacts/feature-technical-notes.md — creating the file lazily if it does not yet exist and at least one T# qualifies under synthesis, or leaving it absent if no qualifying mechanic was captured.D# in artifacts/decision-log.md lists its driving F# IDs (Driven by findings:), its supporting T# IDs (Linked technical notes:), dependent decisions, and the spec sections that reference it (Referenced in spec:).F# in artifacts/team-findings.md lists its affected D# IDs (Affected decisions:), affected T# IDs (Affected tech-notes:), and the spec sections it changed (Changed in spec:).T# in artifacts/feature-technical-notes.md lists its supporting D# IDs (Supports decisions:), driving F# IDs (Driven by findings:), and the spec sections that reference it (Referenced in spec:).feature-specification.md has its inline ([D#](artifacts/decision-log.md#...)) link. Every sentence whose correct behavior depends on a captured mechanic has its inline ([T#](artifacts/feature-technical-notes.md#...)) link.The han-core:project-manager owns the final synthesis — its output is authoritative.
Summarize for the user:
{folder}/feature-specification.md, {folder}/artifacts/decision-log.md, {folder}/artifacts/team-findings.md. Include {folder}/artifacts/feature-technical-notes.md in the list only if it was created.artifacts/decision-log.md).feature-specification.md's ## Deferred (YAGNI) section (omit this line if the section was not written because nothing qualified).artifacts/feature-technical-notes.md) — omit this line if the file was not created.artifacts/team-findings.md).feature-specification.md).Ask whether the user wants to iterate on specific sections or consider the specification ready for implementation planning.
Note for existing specs that predate this rule or need cleanup: this skill authors new specifications from scratch. To clean an existing feature-specification.md against the current spec-content rule (for example, to extract implementation mechanics into a new feature-technical-notes.md), run han-planning:iterative-plan-review on the existing spec file. Its spec-aware mode applies the same rule and roster used here.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.