Getting started¶
This page walks through installing the CLI, scaffolding a project, writing your first node, and adopting the tool on an existing codebase.
Install¶
SpexCode runs on Node 22. Install the CLI, which provides the spex command:
spex init¶
Run init inside an existing git repository. It needs a git work tree and will not create one for you — if the directory is not a repo, it stops and points you at git init before writing anything.
init is additive and never overwrites existing files. It scaffolds three things:
- a starter
.spec/tree with a root node; - the git hooks (a pre-commit check and a commit-message stamp), copied into the repository's hooks directory;
- a
spexcode.jsonat the repository root. Itslint.governedRootsships pointing atsrc— set it to your project's source directories, orspex lintwill report it is governing nothing.
Your first spec node¶
A node is a directory under .spec/ containing a spec.md. The directory name is the node id; nesting one directory inside another makes it a child.
Create one for a piece of code you want governed:
Then write .spec/project/auth/spec.md:
---
title: auth
desc: How a session token is issued and checked.
code:
- src/auth/session.ts
- src/auth/verify.ts
---
# auth
Tokens are issued on login and expire after 24 hours. Verification
rejects an expired or malformed token before any handler runs.
Refresh is explicit; there is no silent renewal.
The body states present intent, not a changelog — you rewrite it in place as the intent changes, and version history comes from git. The code: list is the edge the linter checks.
Run the linter¶
Two checks are errors and block: every path in a code: list must exist, and a body must not carry a ## vN changelog heading. The rest are advisory warnings — coverage (a tracked source file no node claims), drift (a governed file changed after its spec's last version), and a few size and ownership signals. Coverage and drift stay warnings so a partially adopted repository still passes on its errors.
Every project-shaped value — governed roots, file extensions, budgets, limits — is read from spexcode.json under the lint key, so you tune it to your layout rather than forking the tool.
Adopting an existing codebase¶
You do not need to restructure anything. Add nodes for the parts you want governed, each with a code: list pointing at existing files, and use the coverage warnings as your worklist: each one names a tracked source file no node claims yet. Work the list down until the graph is complete.
Because the git hooks are per-clone and bypassable, treat them as fast local feedback and make CI the real gate: run spex lint on every push and pull request, and give CI the full git history, since the version timeline and drift are derived from it.
If your layout differs from the default — main at the repository root, worktrees under .worktrees/, node/<id> branches — describe your structure in spexcode.json rather than changing the repository. An explicit mainBranch is respected; otherwise the source-of-truth branch is detected from the main checkout, falling back to main.