| name | add-functional-specs |
| description | Add multiple functional specs to the ***functional specs*** section of a ***plain spec file in a single batch. Use whenever more than one new functional spec is being added — whether the user explicitly asks, or another skill/workflow (e.g. forge-plain, add-feature) needs to author several specs in one pass. Bulk-writing or hand-authoring functional specs without invoking this skill is forbidden; for adding a single spec, use add-functional-spec instead. |
Add Functional Specs
Always use the skill load-plain-reference to retrieve the ***plain syntax rules — but only if you haven't done so yet.
When to Use
- The user asks for several functional specs to be added in one go (e.g. "add these three specs", "spec out this feature in a few bullets").
- A higher-level skill or workflow (
forge-plain, add-feature, debug-specs) needs to author a tight group of related specs.
- Anywhere you would otherwise be tempted to write more than one functional spec without running per-spec analysis.
If you only need to add a single spec, use the add-functional-spec skill instead. Either way, never edit the ***functional specs*** section by hand — every new entry must go through one of these two skills so the complexity and conflict checks actually run.
Workflow
This skill is add-functional-spec applied one spec at a time, in order, with no shortcuts. The batch never escapes per-spec rigor.
- Identify the target
.plain file. If ambiguous, ask the user.
- Read the entire file to understand existing definitions, implementation reqs, and all current functional specs (including those reachable via
import / requires).
- Draft all the specs you intend to add, in the chronological order they should appear. Keep the drafts in a working list — nothing is inserted yet.
- For each drafted spec, in order:
-
Analyze complexity. Run analyze-if-func-spec-too-complex on the spec. If the verdict is TOO COMPLEX, run break-down-func-spec, replace the entry in the working list with the resulting smaller specs (preserving order), and restart this step on the first of the replacements.
-
Check for conflicts. Run analyze-func-specs once with this single input set:
- the new spec, plus
- every existing functional spec in the file and its
requires chain, plus
- every spec from this batch that has already been inserted.
The batched analyzer returns every conflicting pair in one call — do not loop over pairs invoking a per-pair analyzer. For each conflicting pair it reports, run resolve-spec-conflict. Apply the resolution — which may revise the new spec, an existing spec, or both — then re-run analyze-func-specs once over the touched set until the verdict is COMPATIBLE.
-
Append the spec to the ***functional specs*** section. Specs are chronological; the new entry goes at the end (unless an earlier existing spec must come after it — in that rare case, insert at the correct position).
- Read the file again to confirm correct placement, ordering, and syntax for the full batch.
Order matters: each new spec is inserted only after its complexity and conflict checks pass, so subsequent specs in the batch are always checked against an already-validated file.
Rules
All the rules from add-functional-spec apply per individual spec. They are restated here so this skill is self-contained.
Complexity Limit (per spec)
Each functional spec must imply a maximum of 200 changed lines of code. If a spec is too large, use break-down-func-spec to split it into multiple smaller, independent specs. Do not include LOC estimates in the spec text.
Chronological Ordering
Specs are rendered incrementally, top to bottom. The renderer has no knowledge of future specs — only previously rendered specs are in context.
- A new spec can reference behavior defined by earlier specs.
- A new spec cannot assume anything about specs that come after it.
- Order the batch so that each spec only depends on specs that precede it. If two new specs would otherwise reference each other, the dependent one comes second.
Language Agnosticism
Write in terms of behavior, concepts, and domain logic — not implementation constructs. Avoid language-specific types, generics syntax, framework annotations, or other constructs tied to a particular language or framework. General technical terms (null values, JSON types, HTTP status codes) are fine. Language-specific guidance belongs in ***implementation reqs***.
No Conflicts (full coverage via one batched call per spec)
The new specs must not contradict each other and must not contradict any existing functional spec. Conflicting specs are the most costly outcome. The conflict check must cover:
- every (new × existing) pair, and
- every (new × new) pair within the batch.
That coverage is achieved by running analyze-func-specs once per spec being inserted, with the new spec plus every existing spec plus every already-inserted spec from this batch passed in as a single set. The batched analyzer lists every conflicting pair in one call — do not invoke a pair-by-pair analyzer. If ambiguity exists, add explicit detail to eliminate any conflicting interpretation. For each conflicting pair the batched analyzer reports, use the resolve-spec-conflict skill to diagnose and fix it before proceeding.
Disambiguation (per spec)
Each functional spec must be unambiguous — the renderer should have only one reasonable interpretation. If a single line is not enough to fully disambiguate the behavior, use nested sub-bullets to add detail. Nested lines clarify the parent spec; they do not introduce separate functionality. Even with nested detail, the spec must still imply ≤ 200 LOC.
- :User: should be able to send a :Message: to a :Conversation:.
- A :Message: must have non-empty content.
- The :Message: is appended to the end of the :Conversation:.
- All :Participant: members of the :Conversation: can see the new :Message:.
Line syntax (hard rule, per spec)
Every line inside ***functional specs*** must be its own list item starting with - . ***plain has no concept of bare continuation lines — indented prose without a leading - is invalid syntax and the renderer will reject the whole file.
- Hard limit: 120 characters per line. If a sentence is too long, split it at a natural clause boundary into nested
- bullets — never wrap onto an unprefixed line.
- Nested clarifications are also
- items, indented under the parent. The indentation alone is not enough; the leading - is required.
- This rule applies to every spec in the batch — one bad continuation line invalidates the entire insert.
BAD — bare continuation lines (invalid ***plain syntax, will not render):
- :GatewayWebhook: should hand off :StripeRequest: to :StripeIntegration:.handle(),
which returns a list of :EventEnvelope: dicts conforming to the gateway's
contract.
GOOD — every line starts with - :
- :GatewayWebhook: should hand off :StripeRequest: to :StripeIntegration:.handle().
- The method returns a list of :EventEnvelope: dicts.
- The dicts must conform to the gateway's :EventEnvelope: contract.
Deterministic Interface
Specs must be detailed enough that a developer can use the built software without reading the generated code. All external interfaces must be explicit — REST endpoint paths and HTTP methods, CLI command names and arguments, file formats, message schemas, etc. Never leave interface details up to the renderer's discretion.
Encapsulation
Functionality must be self-contained in the spec text. requires modules only import functional specs, so do not rely on implementation reqs to convey behavior — they won't be visible in downstream modules.
Acceptance Tests
If any of the newly added functional specs need verification, use the add-acceptance-test skill to add acceptance tests after the batch has been inserted. Do this per spec, not as part of the bulk pass.
Anti-Patterns
- Don't skip per-spec checks because the batch "feels" small. Even two specs require two complexity checks and a batched conflict check that includes both new specs.
- Don't fall back to pair-by-pair conflict analysis. Use
analyze-func-specs with the full relevant set once per inserted spec — not analyze-2-func-specs across every pair.
- Don't run all complexity checks first and all conflict checks last. Interleave them per spec, as described in the Workflow — a failed complexity check earlier would otherwise waste later conflict checks.
- Don't insert every spec first and then analyze. A bad spec already in the file pollutes subsequent conflict analyses.
- Don't fall back to hand-authoring because there are "a lot" of specs to add. The right answer is more analyzer calls, not fewer.
- Don't use this skill for a single spec. Use
add-functional-spec — it's the same checks without the bulk bookkeeping.
Validation Checklist