Schema reference

Generated from the live contract module — always in sync with the editor and skill.

Overview

A SpecPad project lives in docs/specpad/ inside your git repository and consists of up to five JSON files:

FilePurpose
[name].proj.json Project index — names the system and lists the SRS/VTP documents that belong to it.
[name].srs.json Software Requirements Specification — ordered requirements and section headings.
[name].vtp.json Verification Test Plan — ordered tests, each linking to the requirements it verifies.
[name].releases.json (sidecar) Release manifest — one entry per git tag, with snapshot paths for change-tracking.
[name].job.json (sidecar) Current-job marker — the active ticket or issue number attributed to in-flight spec changes.

Snapshot files are cached under docs/specpad/.specpad/; that sub-folder is regenerable from git history and is never the source of truth. Each release entry carries a snapshot path (or null if not yet cached) pointing to the corresponding raw document copy.

Schema versioning

Every file carries a schemaVersion field. Version "1.0" maps to the pinned editor build at /v01/. When a new schema version ships, its editor build is deployed at a new path (e.g. /v02/) and the old path remains live forever — so existing documents always open in an editor that understands them.

What is and isn't stored

Git owns history. The files contain no modifiedBy, modifiedDate, author, or change-list fields — git commits carry that context. Nothing derived is stored. Test counts, pass/fail roll-ups, and change diffs are computed on read from the raw JSON; storing them would create a drift hazard.

Field reference

Field descriptions are authoritative — they are read directly from the JSON Schema definitions at build time. A missing description is a build error.

project

FieldTypeRequiredDescription
schemaVersion const "1.0" required Contract version of this file; "1.0" documents open in the pinned editor build at /v01/.
type const "project" required Document discriminator; selects the schema this file is validated against.
name string required Short system name; also the filename stem ([name].proj.json).
title string required Human-readable project title shown in the editor.
description string optional Optional free-text summary of the system under specification.
editorBaseUrl string optional Optional base URL the generated launcher opens (e.g. "https://specpad.internal.corp" for a self-hosted server). Absent uses the public hosted editor; the version path is always derived from schemaVersion.
editorProjectId string optional Optional project id on a self-hosted server that hosts several projects, so this repository's launcher opens its own project. Absent opens the server's only project.
safetyClass "A" | "B" | "C" optional The software safety class (IEC 62304 4.3). Declared, not derived: authoring stays at maximum rigor whatever it says, so this records the judgement rather than switching content off. Material beyond the declared class is highlighted as advice, never dropped.
safetyClassRationale string optional Why that class — the injury the software could contribute to, and the reasoning that places it. 4.3 asks for the rationale as much as the classification.
enforce array of string optional Advisory governance rules this project has chosen to be held to. Naming a rule here moves its findings from advice into the blocking result, so a team adopts a practice when ready rather than on the day the rule ships.
documents array of objects required The SRS and VTP files that make up this project.
documents[].type "srs" | "vtp" | "prd" | "sdd" | "risk" | "soup" | "threat" required Which kind of document this entry points at: "srs", "vtp", "prd", "sdd", "risk", "soup", or "threat".
documents[].path string required Path of the document file, relative to the project index.
documents[].title string required Display title for the document.

prd

FieldTypeRequiredDescription
schemaVersion const "1.0" required Contract version of this file; "1.0" documents open in the pinned editor build at /v01/.
type const "prd" required Document discriminator; selects the schema this file is validated against.
name string required Short system name; also the filename stem ([name].prd.json).
title string required Human-readable document title.
items array of objects required Ordered list of product requirements and section headings.
items[].id string required Stable machine identifier, generated once and never changed; SRS satisfies references target it.
items[].code string optional Human-facing label (e.g. "PROD-1"); freely renameable because references never use it.
items[].text string required The product requirement / user need statement.
items[].heading boolean optional True when this item is a section heading rather than a product requirement.
items[].level integer optional Indent depth for hierarchy; absent means 0. Headings form dotted section codes.
items[].status "proposed" | "implemented" optional Lifecycle: "implemented" (realized — must trace down to >=1 SRS requirement, enforced by prd-coverage) or "proposed" (approved intent not yet allocated; roadmap/vision, exempt from coverage). Absent is treated as not-yet-implemented (exempt).

srs

FieldTypeRequiredDescription
schemaVersion const "1.0" required Contract version of this file; "1.0" documents open in the pinned editor build at /v01/.
type const "srs" required Document discriminator; selects the schema this file is validated against.
name string required Short system name; also the filename stem ([name].srs.json).
title string required Human-readable document title.
items array of objects required Ordered list of requirements and section headings.
items[].id string required Stable machine identifier, generated once and never changed; all cross-references target it.
items[].code string optional Human-facing label (e.g. "DOC-1"); freely renameable because references never use it.
items[].text string required The requirement statement.
items[].heading boolean optional True when this item is a section heading rather than a requirement/test.
items[].level integer optional Indent depth for hierarchy; absent means 0. Headings form dotted section codes.
items[].satisfies array of string optional Ids of the PRD product requirements this requirement satisfies — ids, never codes, so renames cannot break the upward trace. Empty/absent unless a PRD register is in use.
items[].design array of string optional Ids of the SDD sections that implement this requirement — the downward trace (IEC 62304 5.4; FDA SDS). Ids, never codes, so a section can be retitled or rewritten without breaking the link. Empty/absent unless an SDD is in use.
items[].securityControl array of any optional Which FDA security control categories this requirement implements (Cybersecurity in Medical Devices, February 2026, V.B.1 and Appendix 1). A list, because one requirement often serves several. Distinct from category: 5.2.2 e) says a requirement is a security requirement, this says which control it is.
items[].draft boolean optional Drafted by a tool and not yet ratified by a person. The baseline generator sets it on everything it writes; a reviewer clears it. Without it a scaffold is indistinguishable from a specification.
items[].cites array of string optional What this requirement rests on, so it can be checked rather than believed: a clause of a standard, a source construct, a test that pins it. Free text, because the sources a project cites are not SpecPad's to enumerate — but present, because a review pass verifying a citation needs something to look up.
items[].category array of any optional Which of IEC 62304 5.2.2 a)-l) this requirement is. A list, because A1:2015 NOTE 10 states that the requirements in a) through l) can overlap. Its worth is coverage: a category with no requirement is a question to answer once, not an omission to discover at review.
items[].hazards array of string optional Reserved hazard labels (legacy v1 field; the editor no longer surfaces it).

vtp

FieldTypeRequiredDescription
schemaVersion const "1.0" required Contract version of this file; "1.0" documents open in the pinned editor build at /v01/.
type const "vtp" required Document discriminator; selects the schema this file is validated against.
name string required Short system name; also the filename stem ([name].vtp.json).
title string required Human-readable document title.
items array of objects required Ordered list of tests and section headings.
items[].id string required Stable machine identifier, generated once and never changed; all cross-references target it.
items[].code string optional Human-facing label (e.g. "DOC-1"); freely renameable because references never use it.
items[].text string required The test procedure: what to do to verify the linked requirements.
items[].heading boolean optional True when this item is a section heading rather than a requirement/test.
items[].level integer optional Indent depth for hierarchy; absent means 0. Headings form dotted section codes.
items[].verifies array of string optional Ids of the SRS requirements this test verifies — ids, never codes, so renames cannot break traceability.
items[].expected string optional The expected result that defines a pass.
items[].result "" | "not_tested" | "passed" | "failed" optional Latest recorded outcome for a MANUAL test: "", "not_tested", "passed", or "failed". For automated tests the outcome is derived from a captured run, not stored here. Roll-ups are computed on read.
items[].kind "nominal" | "boundary" | "negative" | "stress" | "security" optional What this test does to the system, as distinct from its level: the happy path, the boundaries, the refusals, sustained load, or testing in a security context. A requirement proven only by nominal tests has been shown to work when nothing goes wrong.
items[].securityTest array of any optional Which of FDA's recommended security testing types this is (Cybersecurity in Medical Devices, February 2026, V.C; vulnerability testing per ANSI/ISA 62443-4-1). Recorded so the set can be produced on request rather than searched for.
items[].draft boolean optional Drafted by a tool and not yet ratified by a person. The baseline generator sets it; a reviewer clears it.
items[].verificationLevel "unit" | "integration" | "system" optional Which verification activity this test belongs to: unit verification (IEC 62304 5.5), integration testing (5.6) or system testing (5.7). Without it a register can show requirements are covered by something, but not that each of the three activities was performed.
items[].notes string optional Evidence and context for the recorded result (free text; the machine link lives in automation).
items[].automation array of objects optional Framework-agnostic links to the automated test(s) that execute this verification. Absent/empty means the test is manual. The result for an automated test is derived from a captured run, never hand-set.
items[].automation[].runner string required Opaque test-runner id (e.g. "vitest", "playwright", "pytest"); interpreted by a runner adapter or CI, never by the SpecPad core.
items[].automation[].file string required Path to the test file (tracked in git), relative to the repo root.
items[].automation[].selector string optional Runner-interpreted identifier for the test or group of tests within the file (a test name, a group/describe name, "#15", …). A result answers a selector when its name equals it or begins with it at a word boundary, so naming a group matches every test beneath it. Absent matches the whole file.

sdd

FieldTypeRequiredDescription
schemaVersion const "1.0" required Contract version of this file; "1.0" documents open in the pinned editor build at /v01/.
type const "sdd" required Document discriminator; selects the schema this file is validated against.
name string required Short system name; also the filename stem ([name].sdd.json).
title string required Human-readable document title.
items array of objects required Ordered list of detailed-design sections: one per software unit (IEC 62304 5.4.2), plus the cross-cutting design views a per-unit walk cannot express (IEEE 1016 viewpoints).
items[].id string required Stable machine identifier, generated once and never changed; SRS design references target it. This is what lets the section be retitled, reordered, or rewritten without breaking the trace.
items[].code string optional Human-facing label (e.g. "SDD-12"); freely renameable because references never use it.
items[].title string required Section heading — the software unit or design view this section describes.
items[].heading boolean optional True when this item groups sections rather than describing a design.
items[].level integer optional Indent depth for hierarchy; absent means 0.
items[].kind "unit" | "view" optional Whether this section describes a software unit (IEC 62304 5.4.2) or a cross-cutting design view (IEEE 1016 viewpoint). Absent means "unit". Only units may be named as the cause of a risk, and the unit list required by 5.4.1 is derived from this.
items[].body string optional The design, as markdown: what the unit hides, its algorithm and data, interface behaviour for valid and invalid input (5.4.3), and unit acceptance criteria (5.5.3). May embed images and diagrams like the architecture document.
items[].source array of string optional Repository paths this section describes, so the design can be checked against the code it claims to describe.
items[].draft boolean optional Drafted by a tool and not yet ratified by a person.
items[].acceptance string optional What "verified" means for this unit (IEC 62304 5.5.3; at Class C also 5.5.4 — event sequencing, resource use, fault handling, boundary values). A field rather than a line of prose, because 5.5.3 is asked per unit and buried in the body it cannot be rolled up or shown.
items[].segregatedFrom array of string optional Ids of other design sections this unit is segregated from, where the separation is essential to risk control (IEC 62304 5.3.5). Ids, never codes.
items[].segregationRationale string optional Why the segregation holds. A1:2015 asks how effectiveness is ensured, not merely that separation was intended.

risk

FieldTypeRequiredDescription
schemaVersion const "1.0" required Contract version of this file; "1.0" documents open in the pinned editor build at /v01/.
type const "risk" required Document discriminator; selects the schema this file is validated against.
name string required Short system name; also the filename stem ([name].risk.json).
title string required Human-readable document title.
items array of objects required The software risk analysis (IEC 62304 clause 7): hazardous situations software can contribute to, and section headings. Hazards, harms, probability estimation and benefit-risk belong to the system risk management file, referenced by hazardRef.
items[].id string required Stable machine identifier, generated once and never changed.
items[].code string optional Human-facing label (e.g. "RISK-4"); freely renameable because references never use it.
items[].text string required The hazardous situation, stated in terms of what the software does or fails to do.
items[].heading boolean optional True when this item is a section heading rather than a risk.
items[].level integer optional Indent depth for hierarchy; absent means 0.
items[].hazardRef string optional Identifier of the hazard or hazardous situation in the system risk management file, which the quality system owns. SpecPad holds the software slice and references the rest rather than restating it.
items[].severity "negligible" | "minor" | "serious" | "critical" | "catastrophic" optional Severity of the resulting harm. There is deliberately no probability: for software you cannot argue probability down, so severity drives the analysis. ISO 14971 leaves the scale to the manufacturer; a project using a different one maps onto this.
items[].sequence string optional The sequence of events that turns the software failure into the hazardous situation (IEC 62304 7.1.5; 7.3.2 for a sequence a control introduces). The analysis rather than decoration: recording only the endpoint hides every step a control could break.
items[].causes array of string optional Ids of the software items that could cause this hazardous situation (IEC 62304 7.1): SDD sections of kind "unit", or SOUP components whose anomalies could contribute (7.1.2). Ids, never codes.
items[].controls array of string optional Ids of the SRS requirements implementing the risk control measures (IEC 62304 7.2; 5.2.2 requires a control implemented in software to be a software requirement). Their verifying tests are the evidence the control works (7.3), derived rather than restated.
items[].justification string optional Why no software control is needed, when there is none — for example a risk controlled in hardware, by labelling, or accepted at system level.
items[].residual "acceptable" | "unacceptable" | "not_assessed" optional The judgement recorded once the controls are in place. Absent is treated as not assessed.
items[].notes string optional Free-text analysis notes.

soup

FieldTypeRequiredDescription
schemaVersion const "1.0" required Contract version of this file; "1.0" documents open in the pinned editor build at /v01/.
type const "soup" required Document discriminator; selects the schema this file is validated against.
name string required Short system name; also the filename stem ([name].soup.json).
title string required Human-readable document title.
items array of objects required The third-party software the product depends on, assessed (IEC 62304 SOUP; FDA off-the-shelf software). Not an SBOM: an SBOM is a recursive inventory of every dependency generated from the manifests, while this is the set that has been assessed.
items[].id string required Stable machine identifier, generated once and never changed; a risk naming this component as a cause targets it.
items[].code string optional Human-facing label (e.g. "SOUP-3"); freely renameable because references never use it.
items[].name string required The component's name, as its supplier calls it (IEC 62304 8.1.2).
items[].heading boolean optional True when this item is a section heading rather than a component.
items[].level integer optional Indent depth for hierarchy; absent means 0.
items[].vendor string optional Manufacturer, project or source of the component (IEC 62304 8.1.2; FDA "manufacturer").
items[].version string optional The exact version in use, including patch level or upgrade designation. Exact rather than a range: an anomaly evaluation is only valid for the version it was performed against (IEC 62304 8.1.2; FDA "version level, patch number, upgrade designation").
items[].releaseDate string optional Release date of that version (FDA).
items[].license string optional Licence the component is distributed under.
items[].url string optional Where the component and its documentation come from.
items[].purpose string optional What the component does in this product, and why it is appropriate for the job (FDA: functional role, purpose, and at Enhanced level the justification for selecting it).
items[].requirements string optional The functional and performance requirements placed on the component, necessary for its intended use (IEC 62304 5.3.3). Text rather than SRS entries: these are requirements on a supplier, not behaviour this product implements.
items[].runtime string optional Hardware and software the component itself needs in order to run (IEC 62304 5.3.4; FDA computer system specifications).
items[].limitations string optional Expected design limitations — what the component is known not to do (FDA).
items[].endOfLife string optional Date the supplier's support for this component ends, where it is known (FDA: end-of-life support plans and obsolescence). A date rather than prose, so a component already past support can be found rather than read for.
items[].endOfLifeSource string optional Where the end-of-life date came from — a URL or citation. An undated claim about a supplier's intentions is not evidence.
items[].usedBy array of string optional Ids of the SDD sections for the units that use this component.
items[].tests array of string optional Ids of the VTP items exercising this component, where its behaviour is verified directly (FDA testing).
items[].maintenance string optional The supplier's development and support practices, and the plan for when support ends — obsolescence contingency (FDA, Enhanced documentation level).
items[].notes string optional Free-text assessment notes.

threat

FieldTypeRequiredDescription
schemaVersion const "1.0" required Contract version of this file; "1.0" documents open in the pinned editor build at /v01/.
type const "threat" required Document discriminator; selects the schema this file is validated against.
name string required Short system name; also the filename stem ([name].threat.json).
title string required Human-readable document title.
items array of objects required The threat model and security risk analysis, which are one register: assessing a threat and identifying it are the same act (FDA cybersecurity guidance; IEC 81001-5-1; AAMI SW96).
items[].id string required Stable machine identifier, generated once and never changed.
items[].code string optional Human-facing label (e.g. "THR-4"); freely renameable because references never use it.
items[].text string required The threat: what an attacker does, and what it gets them.
items[].heading boolean optional True when this item is a section heading rather than a threat.
items[].level integer optional Indent depth for hierarchy; absent means 0.
items[].asset string optional What is being attacked — the data, function or property at stake.
items[].entryPoint string optional Where the attack enters: the interface or trust boundary it crosses.
items[].category "spoofing" | "tampering" | "repudiation" | "information_disclosure" | "denial_of_service" | "elevation_of_privilege" optional STRIDE category, the classification threat modelling has settled on. Its value is coverage: an entry point with no threat in a category is a prompt to ask why.
items[].exploitability "high" | "medium" | "low" optional How readily the threat can be realised — the access required, the skill, and the opportunity. Exploitability rather than probability: an attacker chooses when to act, so a frequency estimate is meaningless, and a defence is worth what it costs to defeat.
items[].impact "negligible" | "minor" | "serious" | "critical" | "catastrophic" optional Severity of the consequence if the threat is realised, on the same scale as safety severity so the two analyses can be read together.
items[].causes array of string optional Ids of the design units or third-party components presenting this attack surface. Ids, never codes.
items[].controls array of string optional Ids of the SRS requirements implementing the security controls. A control is a requirement, so its verifying tests are the evidence it works — the same mechanism the safety risk register uses.
items[].justification string optional Why no software control is needed, when there is none — for example a threat accepted, or controlled by the deployment environment.
items[].safetyRisk array of string optional Ids of the risk items for the safety risk that exploiting this threat would create. This join is the point of AAMI SW96: a security finding with a patient consequence belongs in the safety risk file as well as here.
items[].residual "acceptable" | "unacceptable" | "not_assessed" optional The judgement recorded once the controls are in place. Absent is treated as not assessed.
items[].notes string optional Free-text analysis notes.

releases

FieldTypeRequiredDescription
schemaVersion const "1.0" required Contract version of this file; "1.0" documents open in the pinned editor build at /v01/.
type const "releases" required Document discriminator; selects the schema this file is validated against.
name string required Project name this manifest belongs to.
tagPattern string required Git tag glob (e.g. "v*") that marks releases of the spec.
baseline string | null required Version whose snapshot the editor diffs the working copy against (the current redline base).
releases array of objects required One entry per matching git tag, oldest first.
releases[].version string required The release tag name.
releases[].ref string required Commit hash the tag points at.
releases[].date string required Commit date (ISO).
releases[].author object required Author of the tagged commit (release-granularity attribution).
releases[].author.name string required Author display name from git.
releases[].author.email string required Author email from git.
releases[].snapshot string | null required Path of the cached snapshot under docs/specpad/, or null if not yet cached.
releases[].anomalies array of objects optional Defects known to be present when this version shipped, each with the evaluation that made shipping acceptable (IEC 62304 5.8.2, 5.8.3).
releases[].anomalies[].text string required The defect, in terms of what a user would experience.
releases[].anomalies[].evaluation string optional Why shipping with it was acceptable — the 5.8.3 evaluation against safety.
releases[].anomalies[].ref string optional Where it is tracked, when it lives in an issue tracker.
releases[].build string optional How this version was built (5.8.5) and what makes that repeatable (5.8.8): toolchain and versions, environment, and where the build procedure lives.

job

FieldTypeRequiredDescription
schemaVersion const "1.0" required Contract version of this file; "1.0" documents open in the pinned editor build at /v01/.
type const "job" required Document discriminator; selects the schema this file is validated against.
jobs array of string optional The active work items current changes are attributed to — job-record ids (with a register) or tracker keys. One commit may carry several; the skill writes one Job: trailer per entry.
job string optional Legacy single active work item; readers normalize it into the jobs list via activeJobIds(). Prefer jobs.
title string optional Optional human-readable summary, meaningful only for a single external-tracker job with no register.

Governance rules

JSON Schema validates structure only (required fields, types, enums). These policy rules run in both the skill and the editor from one shared module (src/shared/governance.ts) — they cannot drift.

traceability — Every requirement is verified

Every non-heading SRS requirement must be referenced by at least one VTP test.

referential-integrity — References resolve

Every VTP `verifies` entry must resolve to an existing SRS item id.

missing-expected — Tests declare an expected result

Every non-heading VTP test must have a non-empty `expected` value.

active-job-open — Active jobs are open

No active-job marker entry may point at a closed job record; reopen it or pick another before attaching more changes.

active-job-known — Active jobs exist in the register

When a jobs register exists, every active-job marker entry must resolve to a record in it (no dangling or mistyped ids).

prd-referential-integrity — PRD references resolve

When a PRD register is present, every SRS `satisfies` entry must resolve to an existing PRD item id.

prd-coverage — Every implemented product requirement is satisfied

When a PRD register is present, every non-heading PRD item marked `status: "implemented"` must be referenced by at least one SRS requirement via `satisfies`. Items that are `proposed` (or have no status) are roadmap/vision and exempt.

sdd-referential-integrity — Design references resolve

When an SDD is present, every SRS `design` entry must resolve to an existing SDD section id.

sdd-coverage — Every requirement reaches the design

When an SDD is present, every non-heading SRS requirement must reference at least one SDD section via `design` — the evidence that the design implements the requirements (IEC 62304 5.4; FDA SDS).

risk-referential-integrity — Risk references resolve

When a risk register is present, every `causes` entry must resolve to an SDD section of kind "unit" or to a component in the SOUP register, and every `controls` entry to an existing SRS requirement. A design view is rejected as a cause: it describes structure across units rather than something that can fail on its own.

risk-cause — Every risk names a contributing software item

When a risk register is present, every non-heading risk must name at least one software item that could cause it (IEC 62304 7.1). A hazardous situation with no software cause does not belong in the software risk analysis.

risk-controlled — Every risk is controlled or justified

When a risk register is present, every non-heading risk must reference at least one controlling requirement (IEC 62304 7.2), or record why no software control is needed — for example a risk controlled in hardware or by labelling.

soup-identity — Every component is exactly identified

When a SOUP register is present, every component must record a supplier and an exact version (IEC 62304 8.1.2). A version range is not an identity: an anomaly evaluation is only valid for the version it was performed against.

soup-requirements — Every component has requirements placed on it

When a SOUP register is present, every component must state the functional and performance requirements necessary for its intended use (IEC 62304 5.3.3).

soup-referential-integrity — Component references resolve

When a SOUP register is present, every `usedBy` entry must resolve to an SDD section and every `tests` entry to a VTP item.

threat-referential-integrity — Threat references resolve

When a threat model is present, every `causes` entry must resolve to a design unit or a component, every `controls` entry to a requirement, and every `safetyRisk` entry to a risk.

threat-assessed — Every threat is assessed

When a threat model is present, every non-heading threat must record an exploitability and an impact. A threat neither of which is stated has been identified but not analysed.

threat-controlled — Every threat is controlled or accepted

When a threat model is present, every non-heading threat must reference at least one controlling requirement, or record why none is needed — for example a threat accepted, or controlled by the deployment environment.

sdd-segregation — Segregation says why it holds

When an SDD is present, a section naming other sections it is segregated from must say why the segregation is effective, and each named section must resolve (IEC 62304 5.3.5, strengthened by A1:2015 — separation intended is not separation ensured).

vtp-negative-path — Requirements are attacked, not only demonstrated

A non-heading requirement whose tests are all `nominal` should also be tested on a boundary, a refusal, or under load. Advisory: a requirement proven only on the happy path has been shown to work when nothing goes wrong, which is the weaker half of the claim — and a near 1:1 register of requirements to tests is the shape that produces it.

sdd-unit-trace — Requirements reach a unit, not only a view

A requirement whose `design` references resolve only to sections of kind "view" should also reach a software unit. A design view describes structure across units and implements nothing on its own — the same reason `risk-cause` requires a unit rather than a view. Advisory rather than blocking, because a genuine model-level invariant can legitimately live only in a view; the point is that it be a decision rather than an accident.

sdd-acceptance — Units say what verified means

When an SDD is present, every section of kind "unit" should state its acceptance criteria (IEC 62304 5.5.3; at Class C also 5.5.4). Advisory: asked per unit, and answerable only by someone who knows the unit.

risk-sequence — Risks state the sequence of events

When a risk register is present, every non-heading risk should record the sequence of events from the software failure to the hazardous situation (IEC 62304 7.1.5). Advisory: it is the analysis rather than a field, and recording only the endpoint hides the steps a control could break.

srs-category — Requirements declare their content category

Every non-heading SRS requirement should declare which of IEC 62304 5.2.2 a)–l) it is — one or more, since A1:2015 NOTE 10 states the categories can overlap. Advisory: the worth of the list is coverage, and a category with no requirement is a question to answer once rather than an omission found at review.

srs-security-control — Security controls say which control they are

A requirement named as a control by a threat should declare which FDA security control categories it implements (Cybersecurity in Medical Devices, February 2026, V.B.1). Advisory: it is asked only of requirements the threat model already relies on, and an adequate-coverage argument is built from these categories rather than from the word "security".

srs-cites — Requirements say what they rest on

A non-heading requirement should record what it rests on (cites) — the construct that implements it, the clause that demands it, the decision it came from. Advisory: a requirement is not wrong for lacking one. But an audit can only check a claim it can look up, and without citations a review of the register is a re-read rather than a verification — which is the weakest check available.

vtp-verification-level — Tests declare their verification level

Every non-heading VTP test should declare whether it is unit verification (IEC 62304 5.5), integration testing (5.6) or system testing (5.7). Advisory: without it a register shows requirements are covered by something, but not that each activity was performed.

Annotated example

A real requirement from SpecPad's own SRS (DOC-1) and its verifying test (TEST-1), showing how the key fields relate.

specpad.srs.json — one item
{
  "id":   "r_a101",
  "code": "DOC-1",
  "text": "The system shall store project documentation as JSON files under docs/specpad/: one project index, one SRS, and one VTP.",
  "tags": ["schema"]
}
specpad.vtp.json — one item
{
  "id":       "t_c001",
  "code":     "TEST-1",
  "text":     "Confirm docs/specpad/ holds the three core files and each parses as JSON.",
  "verifies": ["r_a101"],
  "expected": "All three files exist and parse without error.",
  "result":   "passed",
  "notes":    "dogfood.test.ts"
}
  • id r_a101 / t_c001 — stable machine identifiers generated once and never changed. Renaming code (the human label) never touches id.
  • code DOC-1 / TEST-1 — freely renameable display labels. The editor shows them; the skill increments them; traceability links ignore them entirely.
  • verifies ["r_a101"] — the test links to the requirement by id, never by code, so renaming DOC-1 to ARCH-1 cannot break the link.
  • expected "All three files exist…" — a non-empty expected result is required on every non-heading test (governance rule missing-expected).

Install & use the skill

The SpecPad Claude Code skill lets you create and maintain SRS/VTP documents directly from your AI assistant, with full validation and governance checks.

  1. Download specpad-skill.zip and unzip it into ~/.claude/skills/ so that ~/.claude/skills/specpad/SKILL.md exists.
  2. In any repo, tell Claude Code: "set up specpad" — it scaffolds docs/specpad/ with a project index, an empty SRS, and an empty VTP.
  3. Use natural language to manage your spec. Trigger phrases:
    • write a spec
    • formalize requirements
    • add a requirement
    • write tests for
    • check traceability
  4. Before finishing any task the skill validates structure and runs all three governance rules — so the JSON files on disk are always editor-ready.
  5. Open the same files in the hosted visual editor at specpad.com/v01/ to review, edit, and record test results through a full UI. Git is the shared history layer; both halves read and write the same JSON.