# specfold: full documentation > specfold keeps design, plan, and maintenance docs next to your code, linked as a graph and guarded by checks. --- Source: https://specfold.build/start/ # Tutorial: three steps > [!TIP] > In five commands you get a `spec.toml`, a document that governs a code path, and a passing > `spec check`. Install first: [Install](install.md). ## The steps 1. **Write.** `spec init` writes a starter `spec.toml`; `spec new` stores a document with the owner of the code it governs. 2. **Link.** `--governs` records the code path. `spec context` now lists the document for any file under it. 3. **Check.** `spec check` runs the rules. `spec agents` prints the lines for an agent's instruction file. ## Run it ```console $ spec init --owner 'services/*={1}' --write $ spec new sot --governs services/shop/src/cart --title "Cart totals" $ spec context services/shop/src/cart/total.rs $ spec check $ spec agents --for claude ``` ## What happened The `--owner` pattern makes every directory under `services/` an owner, so the document lands in `services/shop/.spec/sot/`. Its id, `sot:shop/cart-totals`, comes from that place. `spec context` answers the question an agent or reviewer asks first: which documents must I read before changing this file? ## Next - [Document types](../concepts/document-types.md): what to write besides a `sot`. - [Lifecycle](../concepts/lifecycle.md): how a document becomes `active`. - [Editing documents](../guides/editing.md): change documents without hand-editing front matter. --- Source: https://specfold.build/start/install/ # Install > [!TIP] > Pick one method. Each gives you two commands, `specfold` and its short alias `spec`. ## Choose a method ### npm ```sh npm install --save-dev @modootoday/specfold npx spec --version ``` ### cargo ```sh cargo install specfold ``` ### Binary ```sh sha256sum -c specfold-x86_64-unknown-linux-gnu.tar.gz.sha256 tar -xzf specfold-x86_64-unknown-linux-gnu.tar.gz ``` npm downloads only the build for your machine through platform-specific optional dependencies. Do not install with `--omit=optional` or `--no-optional`. cargo builds from crates.io and needs a Rust toolchain. ## Prebuilt targets Download from the [latest GitHub release](https://github.com/modootoday/specfold/releases/latest). Each archive holds `specfold` and `spec` (`.exe` on Windows), the README and the licences. | platform | target | archive | | --- | --- | --- | | Linux x64 (glibc 2.35+) | `x86_64-unknown-linux-gnu` | `.tar.gz` | | Linux arm64 (glibc 2.35+) | `aarch64-unknown-linux-gnu` | `.tar.gz` | | macOS Intel | `x86_64-apple-darwin` | `.tar.gz` | | macOS Apple silicon | `aarch64-apple-darwin` | `.tar.gz` | | Windows x64 | `x86_64-pc-windows-msvc` | `.zip` | Archive names are `specfold-` plus the extension. glibc 2.35 covers Ubuntu 22.04 and newer. ## Verify the download Every archive has a `.sha256` file next to it. ```sh sha256sum -c specfold-x86_64-unknown-linux-gnu.tar.gz.sha256 # Linux shasum -a 256 -c specfold-aarch64-apple-darwin.tar.gz.sha256 # macOS ``` On Windows, compare `Get-FileHash specfold-x86_64-pc-windows-msvc.zip -Algorithm SHA256` with the `.sha256` file. Put the unpacked directory on your `PATH`. --- Source: https://specfold.build/concepts/ # Concepts > [!TIP] > A document is a Markdown file with front matter. It has a type, an owner, a status and > relations. Together the relations form a graph that `spec check` keeps honest. ## Read in this order 1. **[Document types](document-types.md)** — `sot`, `adr`, `plan` and eight more, and when to use each. 2. **[Lifecycle](lifecycle.md)** — statuses, and why they only move forward. 3. **[Owners and ids](owners-ids.md)** — where a document lives and how its id is made. 4. **[The graph](graph.md)** — relations, `spec context` and `spec graph`. 5. **[Checks](checks.md)** — rules, guards, plugins and audits. 6. **[Times and tasks](times-relations.md)** — timestamps, time zones and task items. --- Source: https://specfold.build/concepts/document-types/ # Document types > [!TIP] > Pick the type by the question the document answers: what holds now (`sot`), why we chose > (`adr`), what we will do (`plan`), or how to do it (`guide`, `runbook`). ## Types There are 11 built-in types. | type | key | what it is | | --- | --- | --- | | sot | slug | a source of truth: the rule that holds now | | adr | timestamp | a decision and the reason for it | | plan | timestamp | a plan of work and its running record | | research | timestamp | a study, benchmark or evaluation | | evidence | timestamp | the cover of a bundle of measurements or raw outputs | | audit | timestamp | an audit snapshot; its body is sealed once committed | | page | slug | the specification of one screen or page | | design | timestamp | a bundle of design boards | | guide | slug | how to develop, operate or use something | | runbook | slug | a step-by-step operational procedure | | change | timestamp | one user-facing change for the release notes | ## Slug or timestamp A **slug** key names something that stays: a rule, a page, a procedure. Its id never changes, and the body is updated in place. A **timestamp** key names something that happened at a moment: a decision, a study, a plan. A new decision is a new document that supersedes the old one, so history stays readable. ## Which one to write - The code must always behave a certain way: write a `sot`, and give it a `verify` command. - You chose between options: write an `adr` and link the `sot` it shapes. - Work spans several commits: write a `plan` with task items. - You measured something: write `research`, and attach raw outputs as `evidence`. - Someone repeats a procedure: write a `runbook`. ## Change the set Projects can disable, change or add types in `spec.toml` under `[types.]`: key, form, statuses, fields, template and transitions. `spec schema ` prints a type's front matter. ```console $ spec schema adr $ spec new adr --title "Round totals half up" ``` Next, see how a document moves through its [lifecycle](lifecycle.md). --- Source: https://specfold.build/concepts/lifecycle/ # Lifecycle > [!TIP] > A document starts as `draft`, becomes `active`, and ends `superseded`, `archived` or > `rejected`. Statuses only move forward, and `spec set` is the only way to change them. ## The flow ```mermaid flowchart LR new([spec new]) --> draft draft -->|spec set status=active| active draft --> rejected active -->|a successor supersedes it| superseded active --> archived ``` ## The statuses | status | meaning | | --- | --- | | `draft` | being written; not binding yet | | `active` | the document that holds now | | `superseded` | replaced by exactly one successor | | `archived` | no longer relevant, kept for history | | `rejected` | a draft that was not accepted | ## Changing status ```console $ spec set sot:shop/cart-totals status=active $ spec set adr:root/20261030 rel.supersedes+=adr:root/20250101 ``` `spec set` writes directly and accepts `--dry-run`. It refuses a jump the type does not allow, and sealed or closed documents. Rule S6 then checks the fields the new status requires. ## What the rules check - **T1**: a superseded document has exactly one successor. - **T2**: status only moves forward, along the type's `transitions`. - **T3**: sealed documents, such as a committed `audit`, keep their body. - **T4**: an edited body moves its `updated` date. - **S6**: a status has the fields it requires. `spec log ` shows the history of a document's status and relations, read from git. ## Custom transitions A type can set its own `transitions` (from → list of to) and `require_when` (status → required keys) in `spec.toml`. `spec explain T2` prints the rule and how to fix a finding. Next: where a document lives, in [Owners and ids](owners-ids.md). --- Source: https://specfold.build/concepts/owners-ids/ # Owners and ids > [!TIP] > Each owner (the repository root, an app, a package) keeps its documents in its own `.spec/`. > A document's id, `:/`, is computed from where it lives. ## Owners Owners are found through package manifests (`package.json`, `Cargo.toml` and others) or `[owners]` patterns in `spec.toml`. A pattern such as `services/*={1}` makes every directory under `services/` an owner named after the directory. `spec new` stores a document with the owner of the code it governs. A document without `rel.governs` stays with the root owner. Rule **P1** reports documents that live with the wrong owner. ```console $ spec owners $ spec new sot --governs services/shop/src/cart --title "Cart totals" ``` ## Ids | part | example | from | | --- | --- | --- | | type | `sot` | the document's type | | owner | `shop` | the owner directory | | key | `cart-totals` | the slug or UTC timestamp | So the file `services/shop/.spec/sot/cart-totals.sot.md` has the id `sot:shop/cart-totals`. A document with chapters or attachments is a directory with `index..md` instead. Rule **S2** checks that the id matches the path, and **I1** that ids are unique across every root. ## Moving `spec mv --slug ` moves or renames a document and rewrites every reference to it. `spec import` brings in a whole layout and writes a frozen alias table, so old ids keep resolving (rules **I2**, **I3**). ## Public paths Published paths, such as a package directory, may hold no spec document (rule **V1**). The `[public]` table names the private owner their documents go to instead. Next: how documents connect, in [The graph](graph.md). --- Source: https://specfold.build/concepts/graph/ # The graph > [!TIP] > Relations are written once, on the document that makes them. specfold derives the graph on > every run, so `spec context` can tell you which documents govern a file. ## Relations | relation | points at | meaning | | --- | --- | --- | | `rel.governs` | code paths | this document rules that code | | `rel.supersedes` | a document | this replaces an older one | | `rel.implements` | a document | this carries out a plan or rule | | `rel.evidence` | a document | this backs a claim with data | | `rel.depends_on` | a document | this needs another to hold | Body references are `[[]]` or `[[#]]`. Rules **L1** and **L3** check that they resolve and point at the right types. ## A small graph A plan implements a source of truth, which depends on a decision. Dashed lines are code paths. This block is the output of `spec graph --format mermaid` on the tutorial repository. ```mermaid graph LR d0["adr:root/20261029190946"] d1["plan:shop/20261029190949"] d2["sot:shop/cart-totals"] d1 -->|implements| d2 d2 -->|depends_on| d0 p0[/"services/shop/src/cart"/] d0 -.->|governs| p0 p1[/"services/shop"/] d1 -.->|governs| p1 d2 -.->|governs| p0 ``` ## Ask the graph ```console $ spec context services/shop/src/cart/total.rs $ spec graph impact sot:shop/cart-totals $ spec graph chain adr:root/20261029190946 $ spec graph consumers org:adr:root/20261030000000 ``` `spec context` lists the documents to read before changing a path. `impact` lists what reaches a document, with the relation and distance. `chain` shows a supersede chain in both directions. `consumers` lists the documents, in this repository and in each `[remotes]` directory on disk, whose relations or pins name a document through a remote. In a shared repository, list the consuming repositories as remotes and run it before changing a shared decision; `--json` feeds a dashboard. Nothing is fetched. ## Draw it in a terminal `spec graph` prints a tree from the documents nothing points at. A document already shown ends in `(*)`, and `--depth N` stops N relations away. ```console $ spec graph sot:shop/cart-totals [draft] ├─ depends_on → adr:root/20261029190946 [draft] │ └─ governs → services/shop/src/cart └─ governs → services/shop/src/cart ``` `--format box` draws layered boxes sized to `COLUMNS`, and falls back to the tree when the graph is too wide or over 60 documents. `--format mermaid` and `--format dot` feed a Markdown renderer or Graphviz. `--ascii` uses plain lines, chosen automatically outside UTF-8 locales. Next: how the graph is kept honest, in [Checks](checks.md). --- Source: https://specfold.build/concepts/checks/ # Checks > [!TIP] > `spec check` runs the rules and reports each finding by rule id with a fix. Guards scan any > file, plugins add rules, and `spec audit` finds what passes yet needs attention. ## How a check runs ```mermaid flowchart LR A[documents + spec.toml] --> B[spec check] B --> C{findings?} C -->|none| D[exit 0] C -->|errors| E[exit 1 + rule ids] E --> F[spec explain RULE] F --> G[spec fix --write] G --> B ``` ## Run the rules ```console $ spec check --staged # before committing $ spec check --new # documents not in the last commit $ spec check --summary # findings per rule; -q lists errors only ``` `spec explain ` says why a rule exists and how to fix it. The full list is in [Rules](../reference/rules.md). ## Unknown keys A front matter key outside the common set and the type's fields is a warning (**S1**). Keep a key for one type with `[types.] fields = [...]`, or for every type with `[check] extra_keys = ["team", "review_*"]`. ## Numbers that stay true A number in prose can name its source, and `spec check` warns when it drifts (**N1**). `spec fix --write` rewrites it. Sources are spec's own counts, never shell commands. ```md We keep 12 active decisions. ``` ## Guards, plugins and audits - **Guards** (`[[guards]]`, `spec guard`) check files and commit messages for denied terms, patterns, files, sizes and secrets. Terms can come from an environment variable and are masked. - **Plugins** (`[[plugins]]`) speak `specfold.plugin.v1` JSON over stdin and stdout. Only programs named in `spec.toml` run. - **Audits** (`spec audit`) report stale documents, orphans, stalled plans and drifted agent assets. `spec audit record` seals a review as an `audit` document. Pin a document to a commit with `spec set verified_at=HEAD`; `spec audit --kind stale` then reports later commits to the governed paths. --- Source: https://specfold.build/concepts/times-relations/ # Times and tasks > [!TIP] > specfold writes every time in UTC and reads common forms, including a few named zones. > Checkbox items in a body are counted as tasks. ## Written times Timestamp keys (`YYYYMMDDHHMMSS`) are UTC. specfold writes `created` and `updated` as RFC 3339 times in UTC, such as `2026-10-30T02:21:00Z`. Times are compared by their UTC day. ## Read times | form | example | accepted | | --- | --- | --- | | date | `2026-10-30` | yes | | RFC 3339 with offset | `2026-10-30T11:21:00+09:00` | yes | | named zone | `2026-10-30 11:21 KST` | UTC, GMT, KST, JST only | | ambiguous zone | `2026-10-30 11:21 CST` | refused | Named zones are a reading aid only. Rule **S5** checks that dates are valid and that `updated` is not before `created`. ## Task items Checkbox items (`- [ ]`, `- [x]`) in a body are tasks. ```console $ spec show plan:shop/20261029190949 $ spec show plan:shop/20261029190949 --tasks ``` `spec show` reports a document's progress; `--tasks` lists each item with its file and line. `spec audit` reports plans whose tasks are all ticked but that are still active, and archived plans with tasks still open. ## Related - [Lifecycle](lifecycle.md): when a plan should move to `archived`. - [Checks](checks.md): the audit kinds. --- Source: https://specfold.build/guides/agents/ # Using with AI agents > [!TIP] > Give the agent the lines from `spec agents`, or serve every command over MCP with `spec mcp`. > Every command takes `--json` and prints the next command to run. ## The agent loop 1. **Read.** `spec context --json` lists the documents that govern a file. 2. **Change.** `spec edit` and `spec set` update a document without hand-editing it. 3. **Check.** `spec check --staged -q` runs before the commit. ## Instructions and MCP ```console $ spec agents --for claude $ spec mcp $ spec help --json ``` `spec agents --for ` prints the lines for an agent's instruction file. `spec mcp` serves every command as an MCP tool over stdio. `spec help --json` describes every command, argument, example and output schema. ## Agent assets Skills, rules, subagents and instruction files (`AGENTS.md`, `CLAUDE.md`) are declared in `spec.toml` and read beside the documents. They carry no ids. ```toml [[assets]] kind = "skill" # skill, rule, agent or instructions path = ".agents/skills" ``` `spec assets` lists what was found and the documents each asset names. `spec check` reports asset front matter (**A1**), duplicate names (**A2**) and paths or `spec` commands that do not exist (**A3**). ## Copies that never drift A tool copy can declare its source: ```toml [[assets]] kind = "skill" path = ".claude/skills" copy_of = ".agents/skills" ``` `spec sync assets` previews the copies; `--write` applies them, only inside roots with `copy_of`. Files the source lacks stay unless `--prune`. `spec audit --kind drift` names copies that differ. ## This site for agents Every page has its Markdown source at `/index.md`, listed in [llms.txt](../llms.txt). --- Source: https://specfold.build/guides/ci/ # Checks in CI and hooks > [!TIP] > Run `spec check --staged` in a pre-commit hook and `spec check` in CI. specfold prints hook > snippets but never installs them itself. ## Steps 1. **Print a hook.** `spec hook print --for git` (or `pre-commit`, `lefthook`, `husky`). 2. **Add it yourself** to the hook manager you already use. 3. **Run the full check in CI**, with guards over the pushed range. ## Commands ```console $ spec hook print --for lefthook $ spec check --staged -q $ spec check $ spec guard --range origin/main..HEAD ``` `spec check` exits 1 on errors, so any CI system can gate on it. `--summary` gives findings per rule, and `--json` gives one object for tooling. ## Adopt gradually `spec check --write-baseline` records today's findings in a committed file, so only new findings fail. `[check] severity` sets a rule to `error`, `warn` or `off`. `[check] strict` lists paths that never get a baseline. ## Verify sources of truth `spec verify` runs the `verify` commands of `sot` documents (rule **X1**). `[verify]` sets the deadline, parallel jobs and the shell. ## In CI `spec check --format` prints a document CI systems read instead of the text: `github` (workflow annotations, plus a table in the step summary), `sarif` (code scanning), `gitlab` (Code Quality) or `rdjson` (reviewdog). The exit code is the same as without it. The repository's `action.yml` installs a release, checks the archive against its `.sha256` file, and runs `spec check`. Pin `version` to a tag from the releases page: ```yaml name: specs on: [pull_request] permissions: contents: read security-events: write # only for the SARIF upload jobs: check: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: modootoday/specfold@ with: format: sarif - uses: github/codeql-action/upload-sarif@v3 if: always() with: { sarif_file: spec-check.sarif.json } ``` On a pull request the action checks only what it changes, from the merge base with the base branch (`changed: auto`, deepening a shallow checkout as needed); `changed: off` checks everything. The release installed is the tag the action is pinned to; pinned to a branch, a commit SHA or used as `./`, the action has no release to match and needs `version: ` (GitHub fills in a composite action's own ref only for release-style pins). `fail-on` limits which rules fail the step, and `fail-on: none` only reports. With `format: github` (the default) the findings show up on the pull request without the upload step. For pre-commit, the repository ships `.pre-commit-hooks.yaml` (`spec-check`, `spec-check-push`); they need pre-commit 4.4.0 or later and `spec` on PATH. --- Source: https://specfold.build/guides/import/ # Importing an existing layout > [!TIP] > Describe the old layout in an import map, review the plan, then apply it. Old ids and paths > keep resolving through a frozen alias table. ## Steps 1. **Start from a preset or write a map.** `spec import --preset adr-tools|madr|log4brains` prints a starter map for those layouts; edit it for your templates and statuses. 2. **Set the alias table.** Applying needs `[aliases] file` in `spec.toml`; old file names, numbers and links resolve through it. 3. **Review the plan.** `spec import --map import.toml` changes nothing. Settle every line marked `!` (the plan's `next` names the `[status]` line to add), then plan again. 4. **Apply.** `--apply` alone previews; `--apply --write` moves everything and writes the alias table. ```console $ spec import --preset madr > import.toml $ printf '\n[aliases]\nfile = ".spec/_aliases.tsv"\n' >> spec.toml $ spec import --map import.toml $ spec import --map import.toml --apply --write $ spec check ``` ## The map | Key | What it does | | --- | ------------ | | `[[sources]]` | `glob`, `exclude`, `type`, `owner`, `key` (`name`, `created`, `first-commit`) and a `name` regex with `key`, `slug` and `alias` groups | | `[status]` | Old status to new status, matched as written, then in lower case | | `[[status_patterns]]` | A regex and a status, for values with more than a word | | `[body]` | Where the body keeps the status and the date | | `[body.links]` | A line phrase and the relation it records | | `[keys]` | Old frontmatter key to new key, `rel.`, or `-` to drop it | | `stem_aliases` | Also record each old file name as an alias | | `strip_title_number` | `# 2. Use X` becomes the title `Use X` | ### Status patterns ```toml [[status_patterns]] pattern = '^superseded by\b(?P.*)$' status = "superseded" ``` The `by` group names the replacing record, such as `[ADR-0002](0002-use-y.md)` or `ADR-0002`. When that record is in the same import, it gets `rel.supersedes` to the old one. When it is not, the row needs a decision. ### Body metadata ```toml [body] status = "section:Status" # first line under "## Status" date = "line:Date" # "Date: 2024-03-01" drop_status_section = false # true removes the Status section once it is in frontmatter [body.links] Supersedes = "supersedes" "Superseded by" = "-" # the newer record lists the link ``` `status` and `date` take `section:`, `bullet: