Skip to content

Releases: modootoday/specfold

v0.4.0

Choose a tag to compare

@github-actions github-actions released this 31 Oct 16:35

0.4.0 makes every write command preview by default: spec new and spec set now write only with --write, like the rest, so add --write where scripts and CI create or change documents. It also adds coverage audits, decision-maker import, [check] link_ignore and safer --write undo for files with uncommitted edits, and fixes about 100 issues across checks, hints and refusals.

Behavior changes

What an existing command does differs from 0.3.0; check scripts and CI that call these.

spec new and spec set now only preview without --write: add --write to every script, CI job and agent instruction that creates or changes documents with them. Like every other write command, a run without --write (or with --dry-run, which does the same) writes nothing, shows the change with its diff, and exits 0 with next: naming the same command with --write; --json reports written: false. Their hints, help, docs and agent skills now give the --write form. The 0.3 stderr warning is gone.

spec check --write-baseline with --rule or --skip is refused with exit 2: a baseline is recorded from a full run only (C181).

Two or more [[guards]] with the same baseline file are refused when the config loads (exit 2, naming both guards): each guard's --write-baseline used to overwrite the other's entries (C184).

A --write (fix, edit, set and the rest) over a tracked file that already has uncommitted edits first copies it to .specfold/trash/<timestamp>/, and its undo: copies that back instead of git stash, which also took the user's own edits; the preview names such files. Files without uncommitted edits keep the git stash undo (C183).

-C <dir> now resolves relative path arguments against <dir>, and next commands include -C <dir>.

Write previews show an update's changed lines as unified-diff hunks (@@ -old,n +new,m @@): changes with an unchanged line between them, such as the refreshed updated: line and an edited section, are separate hunks instead of one block. In --json, update items carry hunks (each with line, old_line, before, after) in place of the top-level before and after; line is still the first changed line.
spec sync --prune previews name the trash folder .specfold/trash/<timestamp>/ instead of the current second, so a preview and the refusal of the same write agree; the write itself uses the second it runs in and prints the real path. The pruned-files note names .specfold/trash/.
spec check --rule/--skip refuse (rc 2) a rule id that does not exist, as --fail-on does; a lower-case id is pointed at its upper-case form (C132).
spec fix --pick refuses (rc 2) an id that is not one of the finding's choices, listing them (C146).
spec log --since must be a real YYYY-MM-DD date, and spec log --type, spec find --type and spec find --status must name a known type or status; others are refused with rc 2 (C148, C153).
--limit 0 is refused (rc 2) by every command that takes --limit; it showed nothing and its --offset hint pointed at itself (C152).
spec new --governs and spec context refuse (rc 2) an empty path or one outside the repository, instead of recording it or suggesting spec new --governs for it (C130).
A guard whose range is not staged, push, all or a git range (a..b) is refused by every command that loads spec.toml, naming the guard; spec doctor reports it as a config finding (C141).

  • An id held by two files (I1, e.g. a .spec/ and a .spec.local/ copy) is refused (exit 2) by every command that takes a document, listing both paths; name one by its path. spec doctor's fix names the path (C139).
  • spec edit --section/--new-section refuses (exit 2) text holding a heading at the section's level or above, which would start or duplicate a section; deeper headings and fenced code are fine (C125).
  • spec import --apply --write refuses (exit 4) while rows marked ! still need a decision, lists them and suggests --force; the new --force imports anyway. Previews are unchanged (C155).
  • spec attach --into refuses (exit 2) an absolute folder or one with ..; it used to write outside the bundle (C142).
  • spec new skill|rule|agent refuses (exit 2) a title with no ASCII words unless --slug is given, and a --slug that is not kebab-case (C147).
  • spec init refuses (exit 2) an --owner-kind with an empty pattern or template, a {n} beyond the pattern's *s, or a suffix other than :manifest, and a --root that is not an owner id (C140).
  • spec set <id> title= refuses (exit 2) emptying the required title (C128).
  • spec export … --dry-run previews and writes nothing (it exported before): it lists files and, over an earlier export, replaces with exit 0; a plugin exporter is not called. spec check -q now shows config warnings too (C114, C115, C116).
  • spec set <plan> status=archived --write refuses with exit 4 while the plan has open tasks and lists them; --force archives anyway, and --dry-run reports them with exit 0.
  • Exit code 4 (CLI-17): a write flag was given but a safeguard refused it, so nothing was
    written (--write over [write] max_files, sync --prune without --yes, a hand-edited
    copy without --force, export over an earlier export or attach to the store without
    --yes). These exited 0 before.
  • spec set <id> key=[a, b] stores a list, not the string "[a, b]".
  • spec sync --prune --write --yes no longer deletes: each pruned file moves to .specfold/trash/<stamp>/ (ignored by git), and the undo line copies it back (cp -Rp .specfold/trash/<stamp>/. .), so a file never committed can be restored. The undo of a sync or copy lists only the files written, not their sources; a successful sync ends with next: git status --short (C100, C101, C106).
  • spec check --write-baseline without [check] baseline says what to add to spec.toml before previewing, with next: spec explain config (C102). --dry-run is accepted on every command guarded by --yes or --write and writes nothing: check and guard ignore it, import previews even with --apply (C120), and export previews instead (C103, C114). An export whose --out is outside the repository suggests ls <out> instead of git status (C104).
  • An invalid spec.toml points to spec explain config (C106).
  • Overwrites need ownership or --force (CLI-4): spec sync assets --write overwrites a copy file only when its content is a version its source has had (git history or now); a hand-edited copy needs --force. spec fetch leaves a different existing file alone and fetches nothing unless --force. init upgrades and export are unchanged.
  • Bulk writes are bounded (CLI-7): [write] max_files = 50 (0 = no bound). When spec mv, fix, sync or import would change more files, the preview says how many and --write alone writes nothing; narrow the scope or add --yes (new on mv, fix and import).
  • One meaning per shared flag (CLI-11): spec guard --tree (was --all), spec find --body (was --text), spec init --owner-kind (was --owner). The old names keep working as hidden aliases with a stderr warning; help JSON lists them under each flag's deprecated_aliases.
  • spec --help and spec help list the 12 core commands (context, find, show, graph, new, set, edit, check, guard, fix, explain, init); spec --help --all / spec help --all list every command. spec help --json, --markdown, --llms and MCP still describe every command; JSON adds core.
  • spec guard --write-baseline without --yes previews the hit counts it would record.
  • CLI conventions CLI-1–CLI-16 (AGENTS.md, tests/cli_contract.rs). Actions that delete,
    overwrite or send files out now need --yes besides their write flag; without it they write
    nothing and next shows the command with --yes: spec sync assets --prune --write,
    spec attach … --write when a file goes to the store, spec export markdown replacing an
    earlier export in --out, and spec check/spec guard --write-baseline.

Added

  • spec audit --kind coverage: with [audit] coverage_types = ["sot"], lists each {#ANCHOR} heading of a current document of those types that no other document cites as [[<id>#ANCHOR]]. Off by default.
  • Import keeps who decided: MADR decision-makers/deciders, consulted, informed and MADR 2/Log4brains * Deciders: body lines become decision_makers, consulted and informed lists, now declared adr fields (no S1 warning).
  • [check] link_ignore: globs of link targets rule L8 skips.
  • A config warning when require_when names a status the type does not have.
  • A config warning when [audit] coverage_types names a type that does not exist.
  • Rules L8 and L9 (warn). L8 checks plain Markdown links and images offline: a relative path
    must exist and a #fragment must match a heading's GitHub slug (repeats get -1, -2) or a
    {#anchor} in the target file; URLs and ids are skipped. L9 flags an image without alt text.
  • New rule S8 (warning): a field that require_when requires for the current status must hold a usable value — not a placeholder ([types.<t>] placeholders, default TBD, Pending, TODO, ?), of the kind declared in fields = { approvers = "people", resolution = "url", review_by = "date", decision = "link" }, and not shared within a distinct = [["authors", "approvers"]] group. fields as a list works as before.
  • spec help --json marks each command's deprecated_aliases (name, use, since). A deprecated name keeps running the new command and warns on stderr (none yet).
  • spec set ID key= with an empty value deletes the key (an emptied rel is removed too).
  • D1 also counts staged deletes and the old paths of renames (p (removed)). Its fix is a runnable spec new change ... --depends-on ID --write; spec explain D1 points to spec check --staged --rule D1. A staged/changed run without documents says so in its summary.
    ...
Read more

v0.3.0

Choose a tag to compare

@github-actions github-actions released this 30 Oct 01:29
  • chore: release specfold 0.3.0
  • docs: editor setup for spec lsp (C32)
  • translation: refuse remote or translated --from, lower-case slug tag (C67-C69)
  • set: --unpin, named pin errors, review_by date and self-exception checks; audit lists overdue exceptions
  • evals: check consumers before changing a shared decision
  • graph: consumers lists documents here and in remotes that name a shared document
  • check: review_by and pins are common keys; document T5 as error
  • pins: pin remote documents by body revision, rule L7, spec set --pin (X2)
  • exceptions: rel.exception_of with review_by, rule T5 (X4)
  • remotes: L6 cites, R1 for remote sources, set --source-rev, doctor lists remotes; translation evals
  • translations: validate lang and source_rev, reject translation chains, warn on duplicate languages, schema keys, census sections (C57-C61)
  • Name documents in other repositories as : through [remotes]
  • Pair translations by place: [translations] layout, rule R2, spec new --translation, spec fix --translations
  • Quiet config warnings outside check/doctor, open a document by its full timestamp, write imported relations as ids, name changed sections of translations, census --fail-on
  • translations: rel.translation_of, source_rev, rule R1, census --translations
  • check: A4 skips the CI runner home, A3 skips git refs
  • import: presets read both spellings, link superseding records, rewrite links, name the next fix
  • skills: cover doctor, lsp/editor/CI, init --upgrade, edit sections, tier, H1/A4/S7; add evals
  • tests: store the MADR 4 fixture's decisions directory under a .fixture suffix
  • S7 names the --new-section command; spec new writes required sections; typo'd [types.*] tables warn
  • import: --preset prints starter maps for adr-tools, MADR and Log4brains
  • import: status patterns for compound values such as 'superseded by ADR-0123'
  • import: read status, date and links from the body ([body] in the import map)
  • help: list find's aliases list and ls
  • A4: check well-known agent files too, sharing H1's file list
  • H1: scan well-known agent files, escape hidden characters in output, one-character LSP range, before/after fix preview
  • check: S7 required sections per type ([types.] sections)
  • check: A4 machine-specific home paths in agent assets
  • cli: check resolves names like resolve, list/ls find, near-miss status and path candidates, fix and show next lines; docs: H1 in rules reference
  • check: H1 reports invisible characters in documents and agent assets, with a removal fix
  • lsp help: spec.run acts on disk; every change re-runs the full check
  • lsp: one quick fix per candidate; offered --write fix commands run through workspace/executeCommand
  • check: name the naming mismatch for unsaved files, mention --stdin-path only when used, explain '-'; lsp: -32700 for bad JSON and a reason on stderr for broken frames; binstall metadata
  • check: accept document ids; clearer error for unknown names
  • lsp: keep the last full check and reuse it until disk or buffers change
  • lsp: offer replacement fixes as quick fix code actions
  • doctor: no spec.toml is a finding; check: next for errors left out by --fail-on; new: full rerun with --slug
  • lsp: diagnostics over stdio; --stdin-path accepts a new file in a spec directory
  • check: --stdin-path for unsaved buffers; clear errors for files that are not documents
  • check: report one file's findings and an editor format; mv --cited-paths reads tracked files
  • Cycle 23: eval fixes (warnings next, sync without agent files, mv --cited-paths, repeated-title warning, word-boundary slugs, graph json, id prefixes), spec init --upgrade
  • Cycle 22: deterministic doctor/guard tests, generated-file guidance, large-corpus regression test
  • Cycle 21: README standardization, llms.txt, doctor phase 2, show splitting, mv --tier, S3/guard hints
  • feat: --max-bytes list budget (MCP default 40000), graph --assets, spec doctor
  • graph impact lists the agent assets that name the document or what reaches it
  • find --open-tasks: documents with unchecked task items, with the count
  • Revert "Merge feat/cycle18"
  • Check published count markers: count_paths for README and docs, with a test
  • Cycle 17: positional title, fail-on none and excluded-error summary, real ids in next, Action version from its own tag, slug next
  • docs: byte-identical twins (md-kit v1)
  • docs: v5 information architecture, md-kit components and touch targets
  • Number repeated fingerprints; action gains fail-on and checks a pull request from its merge base
  • Add a composite GitHub Action that installs a verified release and runs spec check
  • Add check --format github, sarif, gitlab and rdjson; pre-commit hooks use language unsupported
  • Errors carry one runnable next command; missing args and did-you-mean in usage errors; set refuses superseded without a successor and warns unknown keys; non-ASCII titles slug from governs; first --local excludes the local dir from git; graph impact on a path suggests governs; real rule ids in next
  • help --markdown prints a reference page and suggests the nearest name; mv and import refuse [forbid] paths; set no longer guesses a finishing status; init shows a commented count_paths and names spec explain
  • new refuses [forbid] paths and suggests --local; set names reachable statuses and a next command; N1 reads [check] count_paths; help --markdown keeps a blank line before the table
  • docs: fix site layout overflow and the commands table; list the install channels
  • check: N1 compares numbers in spec:count markers with find filters or table rows; spec fix rewrites them
  • graph: --format box draws layered boxes sized to COLUMNS, ASCII on request or non-UTF-8 locale, tree fallback; tests pin the locale
  • graph: tree with relation and distance, impact relations, chain both ways, governs in json, mermaid/dot, --ascii/--depth
  • Status moves name a real way out: a draft is activated before it is superseded; S4 names the status meant for accepted, proposed, deprecated
  • Built-in change type: one user-facing change per note, active until a release archives it with release set (N8)
  • docs: build the site with Jekyll on GitHub Pages
  • spec sync assets: copy each [[assets]] copy_of source over its root; preview until --write, --prune to delete, refuses paths outside the root and symbolic links (A8)
  • [check] extra_keys: frontmatter keys every type may carry, prefix* allowed (S1)
  • docs: set the Pages custom domain (CNAME)
  • verified_at pin: spec set resolves HEAD, audit stale reports commits to governed code since the pin
  • assets name documents: docs list in spec assets, assets field in spec show
  • docs: short README with generated command table, docs/ guides, and drift tests
  • spec agents: name edit, check summary, assets and audit kinds; commit hash in --version
  • feat(edit): --row with --cell COLUMN=VALUE or a whole row; --append adds a missing row
  • feat(new): spec new skill/rule/agent writes id-less templates
  • feat(audit): drift kind for skill copies that differ from .agents/ and CLAUDE.md without @AGENTS.md
  • feat(check): A3 paths and spec commands named in agent assets exist
  • feat(check): A1 asset frontmatter and A2 unique asset names
  • feat(assets): declare agent asset roots in spec.toml and list them with spec assets
  • feat(edit): add --new-section with --after placement
  • feat(audit): report plans whose tasks and status disagree (kind finished)
  • feat(edit): read piped or redirected stdin when neither --text nor --file is given; add --replace
  • feat(check): S1 unknown key names a near key or the spec.toml fields line that declares it
  • fix(edit): rerun hint uses --text= so text starting with '-' still parses
  • feat(dates): write created/updated as RFC 3339 UTC, read plain dates, offsets and UTC/GMT/KST/JST
  • docs: say that timestamp keys and dates are UTC
  • feat(edit): rerun hint quotes the input so it can be pasted
  • feat(fix): resolve a shared alias (I2) by keeping it on the picked document
  • feat(check): --summary counts per rule, -q lists errors only, clearer paging and baseline lines
  • feat(check): --new lists documents not in the last commit; say audit is optional
  • feat(links): match stale path cites by file name and rewrite them on mv
  • feat(edit): replace or append to a section or the whole body
  • feat(show): count task items and list them with --tasks

v0.2.6

Choose a tag to compare

@github-actions github-actions released this 28 Oct 08:48
  • chore: release specfold 0.2.6
  • feat(owners): a pending owner's old layout raises no findings until import
  • feat(check): a moved gitlink brings the files changed inside it into the run

v0.2.5

Choose a tag to compare

@github-actions github-actions released this 28 Oct 02:37
  • chore: release specfold 0.2.5
  • fix(attach): re-attaching a file already in the bundle keeps its content

v0.2.4

Choose a tag to compare

@github-actions github-actions released this 27 Oct 18:32
  • chore: release specfold 0.2.4
  • fix(guards): a whole-tree guard reads every tracked file, ignored or not

v0.2.3

Choose a tag to compare

@github-actions github-actions released this 27 Oct 17:54
  • chore: release specfold 0.2.3
  • fix(check): a baseline is keyed by rule and path, not by the commit it was measured on

v0.2.2

Choose a tag to compare

@github-actions github-actions released this 27 Oct 16:55
  • chore: release specfold 0.2.2
  • fix(verify): read subshells and escapes; a configured shell; L6 reads only id-shaped links

v0.2.1

Choose a tag to compare

@github-actions github-actions released this 27 Oct 16:12
  • chore: release specfold 0.2.1
  • fix: redirections are not commands; the first alias table and the baseline pass

v0.2.0

Choose a tag to compare

@github-actions github-actions released this 27 Oct 15:01
  • fix(skills): eval example cites a source of truth, not a dated plan path
  • chore: release specfold 0.2.0
  • chore: plain gitignore for build output and local files
  • feat(skills): usage skills shipped with the package; root allowlist gitignore
  • docs: install instructions written for people
  • feat(npm): ship the CLI on npm as @modootoday/specfold
  • fix(files): command stores run from the repository root
  • feat(import): wrap raw files into generated documents; drop old-layout files
  • fix(import): chapters and attachments move, not copy
  • fix(import): nested bundles stay with their first rule; stem aliases; path targets keep .md
  • fix(import, links): chapter aliases, clean relation targets, relative paths, external notes
  • perf: guards and checks read only what changed, once
  • fix(guards): an empty published path is a hit, not a clean pass
  • test: neutral fixtures in guard tests (no Korean text, no home paths)
  • feat(guards): published-path scope, path patterns, lookaround, script and code exemptions
  • refactor: one responsibility per file, context directories, no flat roots
  • feat(guards): self-tests, table patterns, allow lists, gzip, empty-scan and baseline
  • feat(check): V1 finds published paths, not only configured ones
  • feat(check): L6, citations outside documents still resolve
  • feat(check): T4, an edited body moves its updated date
  • feat(check): baseline of known findings, strict paths, per-rule severity, --fail-on
  • feat: configurable transitions, status-required fields, supersede cycles, verify runner
  • fix(import): stub-only redirects, home owner fallback, nested history, gitignore globs
  • docs: use neutral example paths (services/, research) in docs and tests
  • ci: name the release approval environment after its registry (crates)
  • feat: first version of specfold