Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

codev

Spec-driven development for Claude Code.

codev adds a thin layer of specifications to a repository, so that you and your coding agent agree on what must be built before a line of code is written — and so that architecture decisions, once made, stop being re-debated on every change.

It has two halves:

WhereWhatExamples
Your terminalThe codev binary: the enginecodev init, codev status, codev archive
The Claude Code chatGenerated skills: the steering wheel/codev-propose, /codev-apply

codev init installs the skills into .claude/skills/. From then on you work mostly in the chat, and the skills drive the CLI for you.

codev never calls a language model. It manages Markdown files, the dependency graph between planning artifacts, validation, and the merging of spec changes. Your agent does the writing; codev tells it what to write, where, and under which constraints.

Why codev

In a repository without specs, intent lives in people’s heads. Code is written on one side, reviewed on the other, and six months later someone digs through commits to rediscover why a behavior exists. codev reverses that: for every significant change, you first write down what you want, review it, then implement it.

What codev gives you:

  • An explicit cycle. Every change goes through propose, apply, sync and archive. Each step has an artifact and a dedicated Claude Code skill. See The workflow.
  • Spec deltas, merged precisely. A change never rewrites a spec wholesale. It declares ADDED, MODIFIED, REMOVED or RENAMED requirements, and codev merges them into the main specs when the change is archived, leaving everything else in the file untouched. This is what makes codev usable on existing code, not only on greenfield projects.
  • Immutable architecture decisions. Accepted decisions (ADRs) are sealed with a hash of their body. codev validate reports any silent rewrite. You change a decision by superseding it, never by editing it.
  • Shared conventions across repositories. A project can inherit context, rules and decisions from another repository, read-only, pinned to a git commit. See Inherited sources.
  • Your team’s language. Artifacts are written in the language set in the configuration, while their structure stays machine-readable. See Artifact language.
  • A single native binary. No runtime to install. Prebuilt binaries for macOS, Linux and Windows, verified by SHA-256 at install time.

Origins

codev is inspired by OpenSpec (MIT), the TypeScript tool that popularized a spec-driven development cycle for coding agents. codev keeps its skeleton, rebuilds it in Rust, and makes its own choices on top.

What codev owes to OpenSpec:

  • The propose → apply → archive cycle, and the idea that a change is the unit of work.
  • Spec deltas with four readable operations — ADDED, MODIFIED, REMOVED, RENAMED.
  • The notion of a capability as a grouping of observable behavior, rather than of files or modules.
  • Workflows and templates kept as data, not code.

What codev does differently:

  • A Rust binary instead of a Node.js package. One prebuilt executable, no runtime.
  • A visible _codev/ folder. Planning artifacts are first-class source files: you read them, diff them and review them. The leading underscore keeps the folder visible to tools such as ripgrep and fd, which skip hidden directories by default.
  • A pure core and an imperative shell. The core library performs no I/O; every decision it makes is testable without a disk. See Architecture.
  • One target, done well. codev targets Claude Code only, where OpenSpec supports many tools.

What is specific to codev:

  • Sealed architecture decisions, with supersession, local deviations from inherited decisions, and promotion of a design decision into an ADR.
  • Read-only inherited sources pinned by git commit in _codev/codev.lock.
  • Skill-side MCP integration: /codev-propose detects a ticket identifier such as PROJ-123 and fetches the ticket through the Jira MCP server configured for the project.
  • A versioned JSON contract on every command, so skills can rely on a stable output shape.
  • Documentation embedded in the binary (codev docs), readable offline.

Built with codev

codev is developed with codev: every change to its repository is planned, reviewed and archived with the tool itself. Its _codev/ folder is a real-world example you can browse:

Where to go next

Installation

codev is a single binary. Prebuilt binaries are published on GitHub Releases for these platforms:

PlatformTarget
macOS, Apple Siliconaarch64-apple-darwin
macOS, Intelx86_64-apple-darwin
Linux, x86_64 (statically linked)x86_64-unknown-linux-musl
Windows, x86_64x86_64-pc-windows-msvc

There are four ways to install it. The first two are the shortest and do not require Rust.

macOS and Linux: install.sh

curl -sSL https://raw.githubusercontent.com/mairistem/codev/main/install.sh | sh

The script detects your OS and architecture, downloads the matching archive and the SHA256SUMS file from the latest GitHub Release, verifies the archive’s SHA-256, and installs the binary to ~/.local/bin/codev. It refuses to install if the checksum does not match, and it creates ~/.local/bin if needed.

When ~/.local/bin is not on your PATH, the script prints the exact line to add to ~/.zshrc or ~/.bashrc:

export PATH="$HOME/.local/bin:$PATH"

To install a specific version, set CODEV_VERSION:

curl -sSL https://raw.githubusercontent.com/mairistem/codev/main/install.sh | CODEV_VERSION=0.6.1 sh

The script requires curl, tar, and sha256sum or shasum.

Windows: install.ps1

In PowerShell 5.1 or later (including PowerShell 7):

iwr -useb https://raw.githubusercontent.com/mairistem/codev/main/install.ps1 | iex

The script downloads the .zip archive and SHA256SUMS, verifies the archive with Get-FileHash, and copies codev.exe to %LOCALAPPDATA%\Programs\codev\.

It does not modify your PATH. When the folder is missing from your user PATH, it prints the command to add it:

[Environment]::SetEnvironmentVariable('PATH', [Environment]::GetEnvironmentVariable('PATH', 'User') + ";$env:LOCALAPPDATA\Programs\codev", 'User')

This writes the user PATH only. Avoid setx PATH "$env:PATH;...": it truncates values longer than 1024 characters and copies the machine PATH into the user PATH. Open a new PowerShell window afterwards so the change takes effect.

To install a specific version:

$env:CODEV_VERSION = '0.6.1'
iwr -useb https://raw.githubusercontent.com/mairistem/codev/main/install.ps1 | iex

Only x86_64 (AMD64) is available prebuilt on Windows. On ARM64, build from source.

Manual download from GitHub Releases

If you prefer not to pipe a script into your shell, download the files yourself from the latest release. Each release contains one archive per target, named codev-<version>-<target>.tar.gz (.zip on Windows), and a SHA256SUMS file.

macOS and Linux. Download your archive and SHA256SUMS into the same folder, then:

# Verify the checksum — on macOS: shasum -a 256 -c SHA256SUMS --ignore-missing
sha256sum -c SHA256SUMS --ignore-missing

tar -xzf codev-*.tar.gz
mkdir -p ~/.local/bin
cp codev-*/codev ~/.local/bin/
chmod 755 ~/.local/bin/codev

Windows. Download codev-<version>-x86_64-pc-windows-msvc.zip and SHA256SUMS, then in PowerShell:

# Verify the checksum
$zip = Get-Item codev-*-x86_64-pc-windows-msvc.zip
$expected = (Select-String -Path SHA256SUMS -Pattern $zip.Name).Line.Split(' ')[0]
$actual = (Get-FileHash $zip -Algorithm SHA256).Hash.ToLower()
if ($actual -ne $expected) { throw "SHA-256 mismatch" }

# Extract and install
Expand-Archive $zip -DestinationPath .
$dst = "$env:LOCALAPPDATA\Programs\codev"
New-Item -ItemType Directory -Path $dst -Force | Out-Null
Copy-Item codev-*\codev.exe $dst

Then add the folder to your user PATH as shown above.

From source: cargo install

With a Rust toolchain (1.89 or later), you can build codev from a clone of the repository. This is the path for contributors and for platforms without a prebuilt binary.

git clone https://github.com/mairistem/codev.git
cd codev
cargo install --path crates/codev-cli

The binary is installed to ~/.cargo/bin/codev.

Check the installation

codev --version

On macOS and Linux, command -v codev shows which binary your shell runs. On Windows, use Get-Command codev. If the command is not found, the install folder is not on your PATH; see the instructions above for your platform.

Shell completions

codev completions <SHELL> prints a completion script to stdout for bash, zsh, fish, powershell or elvish:

# bash
codev completions bash > ~/.local/share/bash-completion/completions/codev

# zsh — then run `compinit`
codev completions zsh > "${fpath[1]}/_codev"

# fish
codev completions fish > ~/.config/fish/completions/codev.fish
# PowerShell, current session
codev completions powershell | Out-String | Invoke-Expression

Requirements

  • Claude Code, to use the skills. The CLI itself works without it.
  • git, only for inherited sources hosted in a git repository.

Upgrading

Run codev self-update:

codev self-update                  # asks for confirmation on a terminal
codev self-update --check          # only report the running and latest versions
codev self-update --version 0.5.0  # a specific version, downgrades included

It downloads the latest release for your platform, verifies its SHA-256 against the release’s SHA256SUMS — as the installers do — and replaces the binary in place. Then, inside a codev project, it runs codev update with the new binary. It needs curl and tar, which macOS, most Linux distributions and Windows 10 or later include.

codev self-update only replaces a binary installed by install.sh, install.ps1 or by hand. When codev was installed with cargo install, built from a clone, or installed by a package manager, it prints the command that upgrades it and changes nothing. It never downgrades unless you pass --version. On Windows, the previous binary is kept as codev.old.exe next to the new one until the next codev command removes it.

codev status tells you when a newer release exists, at most once a day; see Does codev check for updates? to turn that off.

You can still run the installer again, or download a newer release. Then, in each project, regenerate the skills so they match the new version:

codev update

codev update also refreshes codev’s managed sections in CLAUDE.md and the pull request template, and the codev version pinned in .github/workflows/codev.yml, where codev init wrote them. See codev update for how hand-edited skills are handled, and codev doctor to check the result.

Quickstart

This chapter takes you from an empty repository to your first archived change in about five minutes. It assumes codev is installed and that you use Claude Code.

Each step shows the Claude Code way first (recommended), then the plain CLI equivalent, so you can see what the skills do underneath. The command output below is real, with the project path shortened to /home/you/acme-app.

1. Initialize the project

At the root of your repository:

codev init

On a terminal, codev init asks at most two questions — which workflows to install and a free-text context for the skills — then writes the files. Pass --yes to accept every default without prompting, as in this run:

codev init --yes --language en
codev initialized in /home/you/acme-app

  Structure   _codev/ — specs, decisions, changes, schemas
  Skills      codev-propose, codev-explore, codev-onboard, codev-apply, codev-sync, codev-archive, codev-update, codev-configure → .claude/skills/

  Repository integration
    + CLAUDE.md                          created
    + .github/workflows/codev.yml        created
    + .github/PULL_REQUEST_TEMPLATE.md   created

  17 file(s) created, 0 updated

→ Recommended next step: in Claude Code, run /codev-configure.
  Claude will analyze the project and enrich _codev/config.yaml
  (context, per-artifact rules) — ~30 seconds.

Or skip this step and run /codev-propose <an-idea> directly.

Run `codev doctor` to see the 2 setup check(s) still to fix.

This repository has a GitHub remote, so codev also wrote a CI workflow and a pull request template; see step 5 below.

Restart Claude Code (or start a new session) so it discovers the new skills.

What codev init does

  1. Probes the environment, silently: project manifests (Cargo.toml, package.json, pyproject.toml, go.mod, pom.xml), the license file, the presence of .github/workflows/, your locale, and the MCP servers declared in .mcp.json, .claude/settings.json and ~/.claude.json. --no-detect skips the probe.

  2. Asks at most two questions when run on a terminal: which workflows to install (full, minimal, or custom) and a free-text context for the skills. An empty answer to the context question opens $EDITOR on a skeleton. A detected Jira MCP server is confirmed rather than asked for. With --yes, or when stdin is not a terminal (CI, pipes), no question is asked.

  3. Creates the _codev/ tree — specs/, decisions/, changes/, changes/archive/, schemas/ — and a _codev/config.yaml in which every detected value carries a comment saying where it came from:

    # codev configuration — generated by `codev init`.
    # Hand-editable: each non-trivial field carries its source as a comment.
    
    schema: spec-driven
    
    # Language of the prose skills write in artifacts (proposal, design,
    # tasks, specs). Structural keywords such as `## Why` or
    # `### Requirement:` always stay in English.
    # set with `codev init --language`
    language: en
    
    workflows:
      - propose
      - explore
      - onboard
      - apply
      - sync
      - archive
      - update
      - configure
    
  4. Installs the skills into .claude/skills/codev-<workflow>/SKILL.md.

  5. Integrates codev into the repository, unless you opt out:

    • a codev section in CLAUDE.md, created if missing, telling Claude Code that the specs are authoritative and that behavior changes go through /codev-propose then /codev-apply;
    • on GitHub, .github/workflows/codev.yml, which runs codev validate --strict on every push and pull request;
    • on GitHub, a codev section in the pull request template.

    codev’s text sits between <!-- codev:begin --> and <!-- codev:end --> markers and never replaces yours. --no-claude-md, --no-ci, --no-pr-template and --no-integration skip these files. See Repository integration and codev doctor.

  6. Declares inherited sources given with --inherit, and pins the git ones right away. See Inherited sources.

If _codev/config.yaml already exists, codev init leaves it untouched: it only installs or refreshes the skills and the repository integration.

codev doctor then lists what the setup still lacks — here, rules and a first spec — with the command or skill that fixes each item:

codev doctor
codev doctor — /home/you/acme-app

Configuration
  ✗ config.rules     no rules: in _codev/config.yaml
      fix: /codev-configure
  ✓ config.language  language: is set
  ✓ config.keys      no unknown key in _codev/config.yaml
  ✓ config.roles     active roles: analyst, investigator, product, qa, architect, lead, tracer, skeptic, developer, newcomer; on domain: security (security), privacy (personal-data), accessibility (user-interface), performance (performance), ops (operations), migration (migration); disabled: none
  ✓ skills           8 skill(s) installed and current
  ✓ sources          no inherited git source
  ✓ codev_version    no newer codev release known

Planning
  ✗ specs            no main spec in _codev/specs/
      fix: /codev-propose <a change> — documenting existing behavior is planned work too
  ! decisions        no accepted decision (not every project needs one)
      fix: codev decision new "<title>"
  ✓ validate         codev validate reports no issue

Repository
  ✓ claude_md        CLAUDE.md has the codev section
  ✓ ci               .github/workflows/codev.yml runs codev validate
  ✓ pr_template      the pull request template has the codev section
  ! changelog        no CHANGELOG.md
      fix: codev changelog --write

14 check(s), 2 to fix, 2 warning(s)

Note The recommended next step, /codev-configure, lets Claude read your README, contributing guide and a sample of your code, then propose a richer context: and per-artifact rules: for the configuration. It shows a diff and writes nothing without your confirmation.

2. Propose a change

In Claude Code, describe what you want:

/codev-propose add a dark mode that follows the system preference

The skill picks a kebab-case name (here add-dark-mode), creates the change, then writes its four planning artifacts in dependency order: proposal.md, the spec deltas under specs/, design.md and tasks.md. It modifies no code, and stops once the plan is ready for your review.

Underneath, it starts with:

codev new change add-dark-mode --goal "Let users switch the UI to a dark theme"
Change `add-dark-mode` created
  Location  /home/you/acme-app/_codev/changes/add-dark-mode
  Schema    spec-driven

Next step: `codev instructions --change add-dark-mode` shows the artifact to write.

codev status shows which artifacts exist and which are waiting on others:

Change: add-dark-mode
Schema: spec-driven

  [ ] proposal
  [-] specs (waiting on: proposal)
  [-] design (waiting on: proposal)
  [-] tasks (waiting on: specs, design)

Planning: 0/4 artifacts
Next:     proposal

For each artifact, the skill asks codev for everything it needs to write it — the schema’s instruction, the template, the project context and rules, the language, and the files it depends on:

codev instructions proposal --change add-dark-mode
Artifact: proposal (change `add-dark-mode`, schema spec-driven)
Write to: /home/you/acme-app/_codev/changes/add-dark-mode/proposal.md
Language: en — prose only; template keywords stay in English

Instruction:

Write the document that establishes WHY this change is needed.
…

Skills call the same command with --json and receive a stable document instead.

3. Review the plan

Once the skill is done, read the artifacts in _codev/changes/add-dark-mode/. The spec delta is the heart of the plan — it states the behavior the change adds, as testable requirements:

## Purpose

Let users choose the color theme of the interface.

## ADDED Requirements

### Requirement: Theme follows the system preference by default

The application SHALL render with the operating system's color scheme until the user picks a theme.

#### Scenario: No theme chosen yet

- **GIVEN** a user who has never changed the theme setting
- **WHEN** their operating system is set to dark mode
- **THEN** the application renders with the dark theme

Ask Claude for adjustments with /codev-update, or edit the files yourself. Then check that planning is complete and the change is valid:

codev status
Change: add-dark-mode
Schema: spec-driven

  [x] proposal
  [x] specs
  [x] design
  [x] tasks

Planning: 4/4 artifacts
Planning is complete.
codev validate add-dark-mode
change add-dark-mode — _codev/changes/add-dark-mode
  ✓ no issues

1 item(s) validated, no issues.

Note A change with no spec delta fails validation with zero_delta_without_marker. That is deliberate: it keeps specs from being forgotten. A change that really has no behavioral impact — a refactor, tooling, documentation — declares skip_specs: true in its change.yaml.

4. Implement

/codev-apply add-dark-mode

The skill reads tasks.md, works through each unchecked task in order, runs the verification each task names, and checks the box. It stops at the first blocker or ambiguity and asks you. It is the only codev skill that modifies code outside _codev/.

5. Archive

When the tasks are done:

/codev-archive add-dark-mode

Or with the CLI:

codev archive --change add-dark-mode
Archived change `add-dark-mode`

Created:
  /home/you/acme-app/_codev/specs/ui/theme/spec.md

Moved to: /home/you/acme-app/_codev/changes/archive/2026-09-30-add-dark-mode

Archiving validates the change, merges its deltas into the main specs — here it creates _codev/specs/ui/theme/spec.md, since ui/theme is a new capability — and moves the change folder to the dated archive. Commit the result: the main specs now describe the behavior you just shipped.

What’s next

  • Every later change follows the same cycle, from a one-line fix to a capability rewrite. The workflow describes each step in detail.
  • Concepts explains deltas, capabilities and decisions.
  • /codev-onboard gives a read-only tour of codev and of your project’s current state, with a recommended next action.

The workflow

Every change in a codev project goes through the same four steps. Each step has a Claude Code skill, and — except for implementation — a CLI command that does the underlying work.

┌───────────┐    ┌───────────┐    ┌───────────┐    ┌───────────┐
│  propose  │───▶│   apply   │───▶│   sync    │───▶│  archive  │
│ plan it   │    │ build it  │    │ merge the │    │ file it   │
│           │    │           │    │ deltas    │    │ away      │
└───────────┘    └───────────┘    └───────────┘    └───────────┘
StepSkillCLIWrites
Propose/codev-proposecodev new change, codev instructions_codev/changes/<name>/
Apply/codev-apply—Project code, tasks.md checkboxes
Sync (optional)/codev-synccodev sync_codev/specs/
Archive/codev-archivecodev archive_codev/specs/, _codev/changes/archive/

Two more skills support the cycle: /codev-explore to think an idea through before proposing anything, and /codev-update to revise a plan that is already written. See Claude Code skills.

At each step, the agent works in a defined role — product owner, QA analyst, architect, tech lead, skeptical reviewer, developer — with criteria it checks before moving on, and stops where you decide. See Roles.

Propose

Proposing creates a change folder and writes its planning artifacts. With the default spec-driven schema, a change has four artifacts:

ArtifactFileRequiresPurpose
proposalproposal.md—Why the change is needed, what changes, which capabilities are affected
specsspecs/**/*.mdproposalSpec deltas: the behavior added, modified, removed or renamed
designdesign.mdproposalHow to implement it: decisions, alternatives, risks
taskstasks.mdspecs, designThe implementation checklist

The dependencies form a graph: specs and design can be written once the proposal exists, and tasks once both are done. codev status reports each artifact as done ([x]), ready to write ([ ]), blocked on a dependency ([-]) or skipped ([~]). State comes only from which files exist — codev keeps no state file.

In Claude Code, /codev-propose does everything in one pass:

  1. If your request mentions a ticket identifier such as PROJ-123 and a Jira MCP server is configured, it fetches the ticket first. See Jira and other MCP servers.
  2. It creates the change with codev new change <name>.
  3. For each artifact that is ready, it runs codev instructions <artifact> --change <name> --json, studies the relevant code, and writes the file following the template.
  4. It checks traceability between proposal, specs and tasks, then challenges the plan as a skeptical reviewer, writing each finding to the change’s review record, fixing what is unambiguous and listing up to five points to challenge. See Propose.
  5. It stops when planning is complete and presents the plan. It never starts implementing in the same turn.

When writing design.md, the skill receives the architecture decisions currently in effect, so the design follows them — or proposes explicitly to supersede one. See Decisions.

A change that has no behavioral impact — a refactor, a dependency bump, documentation — declares skip_specs: true in its change.yaml. The specs artifact is then skipped, and validation accepts the absence of deltas.

Apply

/codev-apply <name> implements the plan. It reads tasks.md, works through each unchecked - [ ] task in file order, runs the verification the task names (a test, a command, an observable behavior), and checks the box only once it passes. Tests follow your existing test suite first, then your language’s conventions and your rules. Once every task is checked, it re-reads the code the change touched as a newcomer to the project would, joined by the experts the proposal’s domains activate, simplifies what is unambiguous without widening the scope, and lists up to five review notes in its summary. Every finding is kept in the change’s review record, with the author’s answer and the reviewer’s check; what only you can decide is listed at the end. Then it runs the full test suite once.

It stops at the first blocker or ambiguity and asks you rather than guessing. It modifies only the named change, never archives and never syncs: those remain explicit steps for you to request.

apply is the only skill allowed to run arbitrary shell commands, because it has to run your tests. There is no CLI equivalent: implementation is the agent’s job.

Sync

codev sync --change <name>

Syncing merges the change’s deltas into the main specs under _codev/specs/ without moving the change. Use it when another change in progress needs to see a new capability in the main specs, or to review the merge before archiving.

Syncing is idempotent: running it again reports the specs as unchanged. In the usual case you skip this step — archiving syncs for you.

Like archiving, syncing validates the change first and refuses if validation reports an error: nothing is written, and codev validate <name> shows the findings.

Archive

codev archive --change <name>

Archiving closes a change:

  1. It validates the change and refuses if validation reports an error, pointing you to codev validate <name> for the details.
  2. It checks the review record and refuses (review_blocked) if it is missing for a step where review roles were active, or if a high-severity finding is still open or disputed; codev review --change <name> shows what is left.
  3. It merges the deltas into the main specs, exactly as sync does.
  4. It moves the change folder, review record included, to _codev/changes/archive/<YYYY-MM-DD>-<name>/.

The whole merge is computed and checked before the first file is written, so an invalid change or a delta that does not apply — for example a MODIFIED requirement missing from the main spec — is reported before anything on disk changes.

After archiving, the main specs describe the behavior you shipped, and the archived folder records why and how it changed. Commit both — and, if the change has a release note, run codev changelog --write to add it to CHANGELOG.md (see Release notes and CHANGELOG).

Choosing the change

codev status, codev instructions, codev sync and codev archive accept --change <name>. When the project has exactly one active change, you can omit it. With several, codev asks you to choose:

error: several active changes: add-audit-log, rework — specify which one
help: `--change add-audit-log`

Change names are kebab-case: lowercase letters, digits and hyphens, such as add-user-auth.

Validating

codev validate

Without arguments, codev validate checks every active change, every main spec and the decision seals. Pass a change or capability name to check one item, or --changes / --specs to check one family. Errors make the command exit with status 1; with --strict, warnings do too — use it in CI:

codev validate --strict

The checks cover the structure of specs and deltas (every requirement uses SHALL or MUST — or DOIT or DOIVENT — and has at least one #### Scenario:), consistency inside a delta (no requirement both added and modified, no rename colliding with an addition), the zero-delta rule, and the integrity of sealed decisions. See File formats for the rules each file must follow.

Claude Code skills

codev ships eight workflows. codev init and codev update render each one as a Claude Code skill in .claude/skills/codev-<workflow>/SKILL.md. A skill is discovered by Claude Code automatically, and you can also invoke it directly by typing its name as a slash command, such as /codev-propose.

SkillWhat it doesModifies
/codev-proposeCreates a change and writes all its planning artifacts in one pass_codev/changes/<name>/ only
/codev-exploreThinks an idea through, compares approaches, clarifies a needNothing
/codev-onboardIntroduces codev, reads the project’s state, recommends the next actionNothing
/codev-configureProposes a richer context: and per-artifact rules: for _codev/config.yaml_codev/config.yaml, after confirmation
/codev-applyImplements the tasks of a planned change, checking them offProject code and tasks.md
/codev-updateRevises a written planning artifact and keeps the others consistent_codev/changes/<name>/ only
/codev-syncMerges a change’s deltas into the main specs without archivingThrough codev sync only
/codev-archiveValidates, merges and moves a change to the archiveThrough codev archive only

Tool permissions

Each skill declares the tools it may use in the allowed-tools field of its frontmatter. The permissions are part of each skill’s promise: a skill that must not write files is not given the tools to do so.

Skillallowed-tools
codev-proposeBash(codev:*), Read, Write, Edit, Glob, Grep, plus the Jira MCP tool when configured, plus Agent in isolated review mode
codev-exploreBash(codev:*), Read, Glob, Grep
codev-onboardBash(codev:*), Read, Glob
codev-configureBash(codev:*), Read, Write, Edit, Glob, Grep
codev-applyBash(codev:*), Read, Write, Edit, Glob, Grep, Bash, plus Agent in isolated review mode
codev-updateBash(codev:*), Read, Write, Edit, Glob, Grep
codev-syncBash(codev:*), Read
codev-archiveBash(codev:*), Read

Bash(codev:*) lets a skill run codev commands and nothing else. Only codev-apply gets general Bash, because it must run your tests and build commands. codev-sync and codev-archive cannot write files at all: every change they make goes through the CLI.

Agent is Claude Code’s sub-agent tool. codev-propose and codev-apply request it only when _codev/config.yaml sets review: { mode: isolated } (Inline or isolated review): each reviewing role then runs as a sub-agent. No other skill ever requests it. After changing the mode, run codev update; codev doctor reports skills_review_mode until you do. Both skills describe the isolated review in either mode, because a change’s change.yaml may override the project’s mode: without the tool pre-approved, Claude Code asks before starting a sub-agent, and if it cannot start one, the roles review inline.

Update notice

/codev-propose, /codev-apply, /codev-update, /codev-sync and /codev-archive read the update and versionRequirement objects of their first codev status --json. When the project’s codev_version is not satisfied, or a newer codev is available and not snoozed, the skill says so in one line, with the release link, and asks Update now or Later before doing anything else:

  • Update now runs codev self-update --yes, then resumes the action;
  • Later runs codev self-update --snooze — 7 days of silence for that version — then resumes. For an unsatisfied codev_version, nothing is snoozed: the team asked for it.

The question is asked once per action, never in the middle of one: /codev-apply asks it before the first task. /codev-explore, /codev-onboard and /codev-configure never ask; /codev-onboard relays codev doctor, whose codev_version check says the same thing. No skill needs more than Bash(codev:*) for it.

The skills in detail

Propose (/codev-propose)

Turns a request into a complete plan: proposal, spec deltas, design and tasks. It reads the relevant code before writing, grounds the scope in what it finds, and reports contradictions with existing specs instead of settling them alone. It writes the prose in the project’s artifact language.

Once the proposal is written, the instructions it reads list the existing requirements the change likely touches. The skill reads them and modifies those the change alters rather than adding new ones beside them; the list is a starting point, not a complete one.

The request authorizes planning only, even if it says “build” or “fix”: the skill stops once the artifacts are written and waits for you.

Each artifact has an explicit role, declared by the schema and returned by codev instructions — product owner for the proposal, QA analyst for the specs, architect for the design, tech lead for the tasks — with “Done when” criteria the agent checks before moving on. The product owner writes the proposal’s release note for end users, categorized, or None for an internal change. The tech lead’s criteria require the affected documentation to be updated in a task, and every scenario to be covered by an automated test that follows your project’s test conventions. A custom schema defines its own.

At each step it asks codev roles --at <step> for the roles of the step and applies their criteria, your project’s extra criteria included; a step whose role your configuration disables is skipped, and the summary says so (see Configuring roles).

Before presenting the plan, the skill reviews it in two steps:

  1. Traceability — every capability has its spec file, every requirement a nominal and an error or edge-case scenario, every scenario a task whose verification covers it with an automated test, a task updates the documentation when the Impact touches documented behavior, and the proposal’s release note agrees with the plan — every breaking item of What Changes, and every removed or breaking modified requirement, has a BREAKING item. Gaps are fixed in the artifacts.
  2. Contrarian pass — the skill re-reads the plan as a skeptical reviewer: need, scope, specs, decisions, assumptions, tasks, and whether ## Domains ticks every domain the plan touches, along with your project’s rules. The skeptic reviews no domain itself — security, privacy, migration, operations, performance and accessibility are their experts’. The experts whose domain the proposal ticks in ## Domains — security, privacy, accessibility, performance, operations, migration — join this pass with their own knowledge. Before writing ## Domains, the skill reads the domains the change’s diff suggests and ticks each one or keeps it unticked with a reason; the skeptic records a finding for any left unticked. Every finding is written to the change’s review record with its severity and quoted evidence; the author fixes it or disputes it, the reviewer checks each answer once, and the pass never adds scope. In isolated mode, the tracer and each reviewer run as separate sub-agents that never see the conversation, and the skill merges their findings before recording them.

The summary ends with Points to challenge: at most five one-line items across all roles, ranked by severity and tagged with the role that raised them — finding id, status, what, why it matters, which artifact — or “No point to challenge found”, then To decide: the disputes the reviewer maintained and the high-severity findings still open. Start your review there.

If the request mentions a ticket identifier matching [A-Z]{2,}-\d+ and a Jira MCP tool is configured, it fetches the first ticket — read-only, a single call — and cites it at the top of the proposal. See Jira and other MCP servers.

Roles: analyst, investigator, product owner, QA analyst, architect, tech lead, tracer and skeptic — see Built-in roles.

Explore (/codev-explore)

A thinking partner for vague requests, investigations and comparisons of approaches. It reads code and specs but creates no change, no artifact and no file. When the idea is clear, it suggests /codev-propose.

Stance: thinking partner.

Onboard (/codev-onboard)

A read-only tour for someone discovering codev: what the tool does, what the current project contains (specs, active changes, decisions), and the one action to take next — for example /codev-configure on a freshly initialized project. It also runs codev doctor --json and lists up to five missing setup items with their fix, without running any of them.

Stance: guide.

Configure (/codev-configure)

Reads the README, contributing guide, documentation and a sample of the source code, then drafts a context: block and per-artifact rules: for _codev/config.yaml. It shows the diff and writes only after you confirm. It never touches schema, language, workflows, mcp or inherits, and it preserves existing comments.

Its tasks rules include testing rules for your language — framework, where tests live, naming, commands — taken from your existing tests. Only when the project has no tests yet does it fall back on the mainstream conventions of Rust, TypeScript/JavaScript, Python, Go or Java.

While the configuration has no rules:, codev init and codev status recommend running it.

Stance: project setup analyst.

Apply (/codev-apply)

Implements a planned change. It checks that planning is complete, then works through each unchecked task of tasks.md in order, verifies it, and checks it off only once the verification passes. It writes tests like your existing test suite, then by your language’s conventions and your rules. It takes the test command from your configuration, manifest or CI, and asks you when it finds none. Once every task is checked, it reviews the code the change touched as a newcomer would, joined by the experts the proposal’s domains activate: it simplifies what is unambiguous, without widening the scope, and reports up to five review notes, each tagged with its role — a high-severity security or privacy finding is always reported. Every finding goes to the review record and through the same answer loop as the plan’s — in isolated mode, after each reviewer has worked alone as a sub-agent and the skill has merged their findings — and the summary lists what you must decide — including any domain the code now suggests that the proposal neither ticks nor justifies: tick it and its expert reviews the code, or justify it. An expert fixes a clear defect within the change’s scope, with a test, and reports any other behavior change instead of making it. It takes the criteria and knowledge of both steps from codev roles; when no role is active at the review, it is skipped and the summary says so. Then it runs the full test suite once. It stops at the first blocker or ambiguity. It never modifies another change, never syncs and never archives.

Roles: developer, newcomer and experts.

Update (/codev-update)

Revises an artifact that already exists — for example a requirement in a spec delta after review — then checks the other artifacts for ripple effects and reports them. It does not create missing artifacts (that is /codev-propose), does not modify code (that is /codev-apply), and does not touch archived changes. It ends with codev validate.

Stance: editor.

Sync (/codev-sync)

Runs codev sync for a change and reports which main specs were created, updated or left unchanged.

Stance: maintainer of the living specs.

Archive (/codev-archive)

Runs codev archive for a change. If validation reports errors, it stops and points you to codev validate rather than trying to work around them. If the review record blocks archiving (review_blocked), it points you to codev review and never records a decision in your place.

Stance: maintainer of the living specs.

Choosing which skills to install

By default all eight are installed. To install fewer, pick the minimal preset at init time — propose, explore, onboard and configure — or list the workflows you want in _codev/config.yaml:

workflows:
  - propose
  - explore
  - apply
  - archive

Then run codev update. An unknown workflow name produces a warning and is ignored. codev update does not delete skills that are no longer listed; remove their folders from .claude/skills/ yourself.

Editing a generated skill

Each generated SKILL.md records the codev version that produced it and a checksum of its own content. If you edit a skill by hand, its content no longer matches its checksum: codev update detects the edit and leaves the file in place:

  Left in place because edited by hand — rerun with --force to overwrite:
    /home/you/acme-app/.claude/skills/codev-apply/SKILL.md

codev update --force overwrites it with the generated version. Skills from another codev version are always regenerated, and so are skills of this version that codev rendered itself — an earlier build, or the other review mode — since they still match their checksum. A skill generated before checksums existed, of this version, is preserved like an edit: run codev update --force once to give it its checksum — check git diff first, since it also overwrites your real edits, and apply them again after.

Roles

A codev skill is one agent, but it does not do everything in the same frame of mind. Each step is given a role: one question it owns, and “done when” criteria the agent checks before moving on. You and your team approve at defined points — the agent never decides those for you.

Roles are criteria, not role-play. The agent does not pretend to be a product owner; it checks the proposal against the product owner’s list. A role whose criteria are met is done, whatever the prose sounds like. Some roles also carry knowledge — the concrete signals, pitfalls per language and references they need to check their criteria well — see Experts and domains.

Roles are data, not prose buried in the skills. codev serves them: the skills ask codev roles --at <step> at each step and apply what comes back, and codev instructions hands each artifact’s role to the agent. Your project can turn a role off, add its own criteria, and override the activation for one change — see Configuring roles.

Built-in roles

IdNameKindStepQuestion it owns
analystAnalyststepplan.understandWhat must be built?
investigatorInvestigatorstepplan.investigateWhat does the project already do?
productProduct ownerartifact (proposal)plan.writeWhy this change, and what changes?
qaQA analystartifact (specs)plan.writeWhat observable behavior must hold?
architectArchitectartifact (design)plan.writeHow will it be built?
leadTech leadartifact (tasks)plan.writeIn what order, and how is each step verified?
tracerTracerstepplan.traceDo the artifacts agree with each other?
skepticSkepticstepplan.challengeWould the plan survive a reviewer who did not write it?
securitySecurityexpert (domain security)plan.challenge, code.reviewCan an attacker abuse what this change adds?
privacyPrivacyexpert (domain personal-data)plan.challenge, code.reviewDoes this change collect, keep or share personal data only as it must?
accessibilityAccessibilityexpert (domain user-interface)plan.challenge, code.reviewCan everyone use what this change adds, with a keyboard or assistive technology?
performancePerformanceexpert (domain performance)plan.challenge, code.reviewDoes this change stay fast as data and load grow?
opsOperationsexpert (domain operations)plan.challenge, code.reviewCan the team run, observe and roll back what this change adds?
migrationMigrationexpert (domain migration)plan.challenge, code.reviewCan existing data, configuration and consumers move to this change safely?
developerDeveloperstepcode.implementDoes each task work, verified?
newcomerNewcomerstepcode.reviewCan a developer who has not seen the plan follow this code?

The step roles and the experts are built into codev. The artifact roles come from the default spec-driven schema, which declares one role per artifact; a custom schema declares its own, or none.

To read a role’s “done when” criteria, ask codev — they are the list the agent receives:

codev roles --at plan.challenge

codev roles without --at lists every role with its activation; add --knowledge to read a role’s knowledge too. See codev roles.

Steps

StepSkillWhat happens
plan.understand/codev-proposeThe request is understood before the change is created; a ticket such as PROJ-123 is read through the Jira MCP when one is configured
plan.investigate/codev-proposeThe code, tests, configuration and documentation are studied before each artifact is written
plan.write/codev-proposeEach artifact is written, then checked against its role, which codev instructions returns in role
plan.trace/codev-proposeThe artifacts are checked against each other; gaps are fixed in the artifacts
plan.challenge/codev-proposeThe plan is re-read by the skeptic and the experts the change’s domains activate; every finding goes to the review record, the author fixes or disputes it and the reviewer checks the answer; at most five Points to challenge, across all roles and each tagged with its role, and what you must decide end the summary
code.implement/codev-applyEach task is implemented, verified, then checked off
code.review/codev-applyOnce every task is checked, the change’s code is re-read by the newcomer and the active experts; every finding goes to the review record; what is unambiguous is simplified, and at most five Review notes, each tagged with its role, and what you must decide end the summary — a high-severity security or privacy finding is never dropped

The procedure of each step — what to write, the caps, the guardrails — stays in the skill. The criteria and the knowledge come from the role.

Experts and domains

Six experts join the review steps when a change touches their domain. Each one is active at plan.challenge — does the design address the domain? — and at code.review — does the implementation respect it?

DomainExpertLooks at
securitysecurityInput validation at trust boundaries, server-side authorization, secrets, injection, unsafe deserialization, new dependencies
personal-dataprivacyPurpose and minimisation, retention and deletion, data subject rights, personal data in logs, processors and transfers
user-interfaceaccessibilityKeyboard access, focus, text alternatives, form labels and errors, contrast, semantics and ARIA
performanceperformanceQueries in loops, unbounded results, blocking I/O on hot paths, allocations in loops, cost of new dependencies
operationsopsStructured logs without secrets, health and metrics, timeouts and retries, a rollback path, actionable errors
migrationmigrationBreaking changes announced, migration paths, rollout order, reversible schema migrations, deprecation

Domains. The proposal lists the domains the change touches in its ## Domains section — the six above as a list to tick, or the single line None:

## Domains

- [x] security
- [ ] personal-data
- [ ] user-interface
- [ ] performance
- [x] operations — new background worker
- [ ] migration

The product owner checks that every domain the change touches is ticked. codev validate reports an unknown domain (unknown_domain) or a malformed section (domains_invalid) as an error, and a missing section on an active change (domains_missing) as a warning — see File formats.

Activation on_domain. An expert is active at its steps only when the change’s proposal ticks its domain. Without a change — codev roles without --change — or while the proposal has no ## Domains section, it is inactive. codev roles --json says why each active role is active in activatedBy: always, project, change, or domain:<name>. You can still force an expert on or off, for the project or for one change — see Configuring roles.

Knowledge. An expert’s knowledge comes in five sections, always in this order:

  • Scope — what it looks at, what it leaves aside, and what it does not report — for instance, the ops expert asks for no feature flag when deploying the previous version undoes the change, and the performance expert reports no constant-factor saving;
  • Signals — concrete patterns to spot, each with a one-line example;
  • By stack — pitfalls in Rust, TypeScript/JavaScript, Python, Go and Java; codev serves the part for your project’s languages (see Stack filter);
  • References — the authoritative standards, such as the OWASP Top 10, WCAG 2.2, RGAA 4 or the GDPR;
  • Reporting — how to report a finding, with its severity, and what it must name: the failure an operator meets, the attack, the data and who receives it, the existing file or consumer that breaks.

The newcomer carries complexity signals per language, and groups what makes one function hard to follow into one finding; it judges readability, not correctness, and the tests the change has, not those it lacks. The skeptic carries planning smells: it challenges the plan’s logic and evidence — need, scope, specs, decisions, assumptions, tasks, and steps with no way back — and leaves each domain to its expert, checking only that the proposal’s ## Domains ticks every domain the plan touches, so that its expert reviews it. The other step roles carry none. Knowledge is served only to active roles: an expert that is not active costs the agent nothing. Read it with codev roles --at code.review --change <name> --knowledge.

Triggers and suggested domains

Ticking domains is a judgement made while planning, before the code exists. So that a domain the change ends up touching is not missed silently, each expert carries triggers — evidence that a change touches its domain — and codev matches them against the change’s diff.

Three kinds of trigger, in groups that each name the domain they suggest:

  • paths — globs over the changed files, relative to the project root, ignoring case: **/auth/**, **/*.tsx. * stays within a folder, ** crosses folders;
  • manifests — dependency manifest names, at any depth: Cargo.toml, package.json, go.mod;
  • patterns — regular expressions over the lines the diff adds: (?i)\b(ALTER|DROP)\s+(TABLE|COLUMN)\b.
ExpertIts triggers, in outline
securityauth, security, crypto folders, .env files, keys; every dependency manifest; credential names, eval, innerHTML, pickle, shell=True, unsafe {
privacyuser, customer, profile, account models; e-mail, phone, birth date, street address, postcode, SSN, IBAN, IP address, geolocation
accessibilitymarkup, style sheets, components, server templates; aria-*, role=, alt=, form and media elements
performance*.sql, query and repository folders, benchmarks; SQL statements, Promise.all, tokio::spawn, caches, pagination
opsDockerfiles, compose files, CI workflows, Kubernetes, Helm, Terraform, deployment folders, logging configuration; environment variables, timeouts, retries, health checks, metrics
migrationmigrations, schemas, *.proto, *.graphql, OpenAPI, *.d.ts; ALTER/DROP/RENAME, deprecations, serde renames

The built-in patterns favour precision: access_token rather than token (a lexer has tokens), street_address rather than address (a socket has one). What they miss for your project, add with triggers: in _codev/config.yaml.

The diff. codev asks git, locally, for what the branch changed since it left the default branch — origin/HEAD, else main, else master — committed or not, plus the untracked files, limited to the project’s folder. It never contacts a remote. Outside git, without a commit or a default branch — or in a shallow CI clone without the merge-base; use fetch-depth: 0 there — there is no diff: codev says so and suggests nothing, and no command fails because of it.

Some files are left out of every trigger: the planning folder _codev/ and the codev skills (planning), vendored dependencies — node_modules, vendor, third_party (vendored) —, lock files such as Cargo.lock or package-lock.json (lockfile), and generated files such as *.min.js or *.pb.go (generated). Binary files, prose (.md, .txt…) and very large files are matched by their path only (binary, prose, large). The scan stops at 2000 files, 5000 added lines per file, 1 MiB per untracked file and 2 MiB of added lines in total, and ignores lines over 2000 characters; the diff then says it was truncated.

Suggestions. codev roles --change <name> reports the diff and each suggested domain with its state:

  • ticked — the proposal ticks it;
  • justified — the proposal keeps it unticked with a reason on its line;
  • unticked — neither: the proposal must answer it.
## Domains

- [x] security
- [ ] personal-data — the fields matched are test fixtures

codev validate reports each unticked suggestion as the warning domain_suggested, at the domain’s line, naming the trigger and the file that matched; codev validate --strict fails on it. codev archive and codev doctor do not read the diff. The diff is the working tree’s: two active changes on one branch share it. A role set to never brings no suggestion.

/codev-propose reads the suggestions before writing ## Domains, and the skeptic records a finding for each one left unticked. Before the code exists the diff is usually empty, so the review is where it bites: /codev-apply lists every suggestion still unticked under To decide — tick it, and its expert reviews the code, or justify it.

Stack filter. codev detects your project’s languages from its dependency manifests — at the root and up to three folders below it, so a monorepo gets every stack — and the By stack part of the knowledge it serves keeps those languages only. codev roles --json says which in stacks; with no manifest found, everything is kept. codev roles --all-stacks serves every language.

Findings: severity, confidence and the review record

What the reviewing roles find — the skeptic and the experts at plan.challenge, the newcomer and the experts at code.review — is written to the change’s review record, _codev/changes/<name>/review.md, before anything is fixed or reported. Each finding quotes its evidence verbatim at a location codev can check, and carries a severity and a confidence on one shared scale:

SeverityMeaning
highThe change would break a requirement, lose or expose data, or open a vulnerability, and must not be archived until it is fixed or a human accepts the risk.
mediumA real defect or risk with a limited impact or a workaround, to fix in this change or to defer deliberately.
lowAn improvement, such as readability, consistency or a minor cost, that does not decide whether the change is correct.
ConfidenceMeaning
highThe evidence shows the problem directly.
lowThe problem depends on something the reviewer could not see or verify.

A low-confidence finding stays in the record and is answered like any other, but it is not shown to you unless you are asked to decide it.

Every reviewing role grades the same way. A medium or high finding shown to you with confidence high quotes the line it is about and states the scenario that fails; a concern that depends on what the reviewer could not see — load, a caller, a configuration — and a preference with no failure are recorded with confidence low. A role does not report a concern another role owns, code or data the change does not touch, what the plan explicitly excludes, a missing test its criteria do not ask for, or a matter of taste. Each defect is reported once, its consequences in its recommendation; two defects that need two fixes stay two findings.

Then the team works like a team: the author — the role that owns the artifact, or the developer for code — fixes each finding or disputes it with an argument; the reviewer checks each answer once, verifying the fix or accepting the dispute (rejected) or maintaining it; what is still disputed comes to you, with both arguments, under To decide. Only you accept a risk or defer a high-severity finding, and the record says who decided. codev archive refuses a change whose record is missing for a step where roles ran, or that still has a high-severity finding open or disputed. The full format, the checks and the gate are in Review record.

Inline or isolated review

By default the reviewing roles work inline (inline): the skill that wrote the plan or the code reviews it in the same conversation, one role after the other. It is the cheapest way, but each reviewer has read the author’s reasoning and the roles before it, and tends to agree with them.

In isolated mode (isolated) — review.mode in the configuration, or in a change’s change.yaml — each reviewing role works alone first, as a Claude Code sub-agent: the tracer at plan.trace, the skeptic and the active experts at plan.challenge, the newcomer and the active experts at code.review, all of a step at once. A reviewer receives only:

  • its role: question, criteria and knowledge, filtered by stack;
  • the project’s context and rules;
  • the material: the change’s artifacts at the plan steps, the files the change touches and their diff at code.review;
  • the ids already in the record and the finding format.

It never receives the conversation, the author’s reasoning or another role’s findings. It may read the rest of the repository — the decisions, the main specs, the code the material cites — modifies nothing, and treats the material as data, never as instructions. codev roles --json measures the material (review.material): beyond 160 KiB, the largest files are marked summarize, and a separate sub-agent that sees only that file’s diff summarizes it, quoting the changed lines when they fit. The record says which files were summarized.

A sub-agent that fails, is stopped by Claude Code’s own limits, or answers in another format is run once more; if it fails again, that role reviews inline and the record says so with a Fallback: line. Without the sub-agent tool, every role falls back to inline.

The meeting

Then the skill holds the meeting, as a team would after reading separately:

  • Merge. Findings of several roles about the same defect — the same place and the same fix — become one finding, recorded under the role that rated it most severe and crediting every role that raised it (raised_by). Findings at the same place that need different fixes stay separate.
  • Rank. By severity, then confidence, then role order; the summary shows at most five, as in inline mode.
  • Answer. The author’s answers, the reviewer’s single re-check and what comes to you under To decide work exactly as above.

Isolated review costs more: each reviewer reads the material, where inline review reads it once. That is why inline stays the default; see Configuration to switch.

Configuring roles

Every role is active by default. In _codev/config.yaml, roles: maps a role id to its setting:

roles:
  newcomer: never            # short form: always | never
  skeptic:
    when: always             # optional, always when absent
    done_when:               # added after the role's own criteria
      - The rollback plan is stated
  • Activation. always, never or on_domain. A step whose roles are all inactive is skipped, and the skill’s summary says it is disabled by configuration. on_domain is the experts’ default; it is refused on a role bound to no domain. Set security: always to have the security expert review every change, or accessibility: never in a project without a user interface.

  • Extra criteria. done_when entries are added after the role’s own criteria, never replacing them. They carry the origin project, like your context and rules.

  • Per change. A change’s change.yaml can override the activation for that change only:

    roles:
      newcomer: always
    
  • What cannot be disabled. The artifact roles (product, qa, architect, lead), the analyst — the guard against a plan built on a misunderstanding — and the developer: their artifact is still written, the request still understood, their tasks still implemented. Their criteria can be extended.

  • Inherited sources do not contribute roles: only your project’s roles: is read.

codev validate reports an unknown role id (unknown_role), an activation other than always, never or on_domain, or on_domain on a role without domains (invalid_role_activation), and never on a role that cannot be disabled (role_not_disableable); codev status, codev instructions and codev roles fail with the same code. codev doctor lists the active roles, the roles active on domain with their domains, and the disabled ones.

Implementing a change (/codev-apply)

Developer (/codev-apply)

Implements the tasks of a planned change, in file order. For each task, it applies the developer’s criteria:

  • the files concerned are read before writing;
  • the code, tests, configuration and documentation the task asks for are written — nothing more;
  • tests are written like the project’s existing suite, then by the conventions of its language and the project’s rules;
  • the verification the task cites is run and passes — the test command comes from context, rules, the manifest or the CI configuration, and the skill asks you when it finds none;
  • only then is the box checked off.

It stops at a material ambiguity or a technical blocker without checking the task off, and describes the options. When every box is checked, and after the review, it runs the project’s full test suite once; a failure is reported instead of the summary. It never works around a failing test, never touches another change, never syncs and never archives.

Newcomer and experts (/codev-apply)

Once every task is checked, and before the full test suite runs, re-reads only the code the change added or modified: the newcomer, as a developer joining the project who has seen neither the plan nor the conversation, and the experts the change’s domains activate, each along its criteria and knowledge. Every finding goes to the review record first. What is unambiguous is simplified and the affected tests are run again; the rest becomes at most five Review notes in the final summary — each tagged with its role and its finding id: what, where, why — or “No review concern found”, followed by what you must decide. A high-severity security or privacy finding is always listed, even beyond five.

The review never widens the change’s scope and never touches code the change did not add or modify. The newcomer never changes behavior. An expert never changes it silently: a behavior-changing fix becomes a review note, unless it is a clear defect within the change’s scope, which is then fixed with a test and named in the summary.

The other skills

The other skills keep a fixed stance, written in the skill itself. These stances are not roles: they are not in the catalog and cannot be configured.

SkillStanceQuestion it ownsWrites
/codev-exploreThinking partnerIs this worth building, and how?Nothing
/codev-sync, /codev-archiveMaintainer of the living specsDo the main specs describe what was planned and shipped?Through the CLI only
/codev-updateEditorIs the revised artifact still consistent with the others?_codev/changes/<name>/ only
/codev-onboardGuideWhere does this project stand, and what comes next?Nothing
/codev-configureProject setup analystWhat must an agent know about this project before writing?_codev/config.yaml, after confirmation

Thinking partner (/codev-explore)

Explores an idea, a problem or a need, without committing to anything. Done when:

  • what the repository already knows comes first — specs, changes in progress, decisions in effect, the relevant code — so you are never asked what the code can answer;
  • the questions asked are about a dependency, a constraint or a trade-off, each with a recommended default answer and why;
  • two or three options are compared, each with what it costs and rules out, and a recommendation is made;
  • a direction that departs from an accepted decision is flagged early;
  • assumptions are stated as assumptions;
  • the exploration ends one of three ways, named: it crystallizes (problem, approach, scope, and an offer to run /codev-propose), information is missing (what, and who can provide it), or it was not worth pursuing.

It writes no file, creates no change, and does not implement even when asked.

Maintainer of the living specs (/codev-sync, /codev-archive)

Keeps _codev/specs/ describing the system. /codev-sync merges a change’s deltas without moving it; /codev-archive merges them and moves the change to _codev/changes/archive/<date>-<name>/. Done when:

  • planning is complete — otherwise nothing is run;
  • the merge goes through codev sync or codev archive, never through a file the skill writes itself;
  • the specs created, updated and unchanged are reported (and, for archive, where the change moved).

On a validation error, both refuse: they answer that the change has errors and point to codev validate <name>, without retrying or fixing the change themselves. Any other error is relayed as the CLI wrote it.

Editor (/codev-update)

Revises one planning artifact that already exists in an active change. Done when:

  • the artifact and the others it might affect are read from disk before writing;
  • the revision stays within the artifact’s contract — expected sections, scenario format, checkboxes;
  • the ripple effect is announced: an orphaned or missing spec file after a proposal edit, a task citing a removed requirement or renamed scenario, a design decision that no longer matches, a task contradicting a requirement — with a suggested next action, applied only on your confirmation;
  • codev validate has run and its report is relayed.

It refuses to create a missing artifact, to touch an archived change, or to modify code.

Guide (/codev-onboard)

Introduces codev to someone discovering it. Done when it has shown three blocks: what codev is, the state of the project (counts of specs, decisions and changes, and up to five missing setup items from codev doctor with their fix), and exactly one recommended next action, quoted as the command to type. It is strictly read-only: it never runs a fix, not even codev init.

Project setup analyst (/codev-configure)

Proposes the context: and per-artifact rules: of _codev/config.yaml from the project itself. Done when:

  • the reading stays within its budget — README and CONTRIBUTING in full, at most 5 documentation files, 8 source files and 3 test files;
  • context: holds 2 to 5 factual lines that complement the detected stack;
  • rules: holds 1 to 2 rules for specs, design and tasks, each positive, checkable on review and grounded in what the project does, plus testing rules taken from the project’s existing tests;
  • the diff is shown and you are asked before anything is written.

It writes only on your yes, changes only context: and rules:, keeps every other field and comment, and refuses if _codev/config.yaml does not exist.

Measuring the roles

codev’s own repository measures the built-in reviewing roles — the skeptic, the tracer, the newcomer and the six experts — with an evaluation suite, evals/. Each case is a small project with a planned change: either seeded with defects the role should find, each with its expected severity and location, or a clean control holding none. The suite has Claude Code run one skill step on each case with the evaluated role alone, then scores the review record it wrote:

  • true positives and misses — the seeded defects found or not. A finding counts for a defect when its role, its location (two lines of tolerance, the same heading of the plan, or another place the case allows) and its category agree: each seeded defect names a category of issue, such as access-control or keyboard-trap, recognised by its terms in the finding’s title or recommendation. A finding about a neighbouring issue two lines away does not stand for the defect;
  • false positives — high-confidence findings that match no seeded defect, in a control or next to the defect; the report marks those found at a defect’s place but naming another issue. Low-confidence findings, which are never shown to you, are counted apart;
  • evidence validity — the share of findings whose quoted evidence codev review finds at the cited lines;
  • severity agreement — the found severity equals the expected one.

The tracer, which fixes the plan instead of recording findings, is scored on the plan it leaves: the missing task added, a complete plan left unchanged.

The cases are written to make a careless reviewer miss: subtle defects next to code that does the same thing correctly (an authorization checked on the list endpoint but not on the detail one, personal data reaching the logs through an error message), cases with two defects of different severity, and controls holding code that looks suspicious but is right (a query assembled from an allow-list with bound values, logs of identifiers that are not personal data). A case’s plan cites only files and tests its project contains, so that a gap in the case is never counted against the role.

The reference scores are the committed baseline, evals/baseline/report.md: five runs of every case, on Claude Code’s default model at the date it names, each score the median of the five runs. A model does not answer the same way twice, so a change to a role file is judged with codev-evals compare --quality-only against the baseline, on the same model: each role’s median must stay within the range the baseline’s runs spanned. The suite never runs in regular CI and is not part of the codev binary.

Reliability of the roles shows those scores, role by role, with the thresholds each role meets or fails and the limits of the measure.

Where you decide

The agent stops and hands over at these points:

  • Clarifying questions. /codev-propose asks before creating a change when an ambiguity would materially change the result, and asks again when an artifact needs a decision or an Open Question changes what needs to be built. /codev-explore asks the questions the code cannot answer. /codev-apply stops at an ambiguity or a blocker and lets you decide.
  • Approving the plan. /codev-propose stops once the artifacts are written. Start your review with the Points to challenge, what is left to decide and the design’s Open Questions; when you are satisfied, ask for /codev-apply. To change an artifact first, use /codev-update.
  • Accepting decisions. A design follows the decisions in effect or explicitly proposes to supersede one. A decision takes effect only when you run codev decision accept.
  • Confirming the configuration. /codev-configure writes only after you answer yes to its diff.
  • Applying a ripple effect. /codev-update reports what else the revision affects; you accept, decline or defer each follow-up.
  • Updating codev. When a newer codev is available or the project requires another version, the skill asks Update now or Later before acting (see Update notice).
  • Configuring the roles. Which review roles run, and which criteria they add, is your project’s choice in roles: — see Configuring roles.
  • Settling the review. A dispute the reviewer maintained, or a high-severity finding nobody could fix, comes to you under To decide: fix it, accept the risk with a justification, or defer it to another change or an issue. The skill records your decision with your name; it never accepts a risk for you. codev review shows what is left.
  • Archiving. /codev-apply never archives: once you have reviewed the implementation, starting with its Review notes, run /codev-archive or codev archive.

Reliability of the roles

codev’s reviewing roles are measured, not assumed. This page shows how they scored the last time the evaluation suite ran, on the run committed in the repository as its baseline. It is generated from that baseline and changes with it.

What the suite measures

The suite is a set of small projects, each with a planned change. A seeded case hides defects a role should find, each with its severity, its location and its category of issue; a clean control hides none. Claude Code runs one skill step on each case with a single role, and the suite scores the review record the role writes: the defects found and missed, the findings that match no defect (false positives), whether each quoted evidence is really at the lines it cites, and whether the severity agrees with the expected one. Measuring the roles gives the rules.

What it does not measure

It is not a benchmark of models, and not a promise that a role finds every defect of your project. It does not measure how useful a correct finding is to you. The plan is measured only as a whole, on the planning cases below, by what it modifies, not role by role. A score describes these cases, on this model, on the day of the run.

The run

  • Date: 2026-10-15
  • Model: Claude Code’s default
  • Claude Code: 2.1.289
  • codev: 0.6.1
  • Cases: 65 (25 seeded, 15 clean controls, 25 planning)
  • Repetitions of each case: 5
  • Cost: 276.46 USD for the 5 runs of each case (55.07 USD for one run of the suite)

At a glance

Recall
1.0039 of 39 seeded defects found
Evidence validity
1.0069 of 69 quotes found at the cited lines
False positives
90.2 per case; a role fails above 2
Roles within the thresholds
8 of 9 1 fail at least one

The run fails its own thresholds. 1 of 9 roles report more than 2 false positives: skeptic. Precision is the roles’ weak point: they report plausible issues that the case does not hold. Reducing these false positives without losing what the roles find is the next work planned on the roles. Every seeded defect was found: on this model, recall does not tell the roles apart, and the differences show in false positives and severity agreement.

False positives per role

False positives per roleHorizontal bars, one per role, sorted by count. The threshold is 2. skeptic: 4 false positives, over the threshold of 2. security: 2 false positives, within the threshold of 2. migration: 1 false positives, within the threshold of 2. ops: 1 false positives, within the threshold of 2. privacy: 1 false positives, within the threshold of 2. accessibility: 0 false positives, within the threshold of 2. newcomer: 0 false positives, within the threshold of 2. performance: 0 false positives, within the threshold of 2. tracer: 0 false positives, within the threshold of 2.01234skeptic: 4 false positives, over the threshold of 2skeptic4oversecurity: 2 false positives, within the threshold of 2security2migration: 1 false positives, within the threshold of 2migration1ops: 1 false positives, within the threshold of 2ops1privacy: 1 false positives, within the threshold of 2privacy1accessibility: 0 false positives, within the threshold of 2accessibility0newcomer: 0 false positives, within the threshold of 2newcomer0performance: 0 false positives, within the threshold of 2performance0tracer: 0 false positives, within the threshold of 2tracer0Threshold: 2
High-confidence findings that match no seeded defect, per role, over every case of the role. The dashed line is the threshold; ▲ over marks a role over it.

Recall and severity agreement per role

Recall and severity agreement per roleTwo meters per role, from 0 to 1. Recall is the share of seeded defects found, with a threshold of 0.50; severity agreement is the share of found defects whose severity is the expected one. accessibility: recall 1.00 (5/5 found), severity agreement 1.00 (5/5). migration: recall 1.00 (5/5 found), severity agreement 0.80 (4/5). newcomer: recall 1.00 (2/2 found), severity agreement 1.00 (2/2). ops: recall 1.00 (6/6 found), severity agreement 0.50 (3/6). performance: recall 1.00 (4/4 found), severity agreement 0.50 (2/4). privacy: recall 1.00 (7/7 found), severity agreement 0.57 (4/7). security: recall 1.00 (6/6 found), severity agreement 1.00 (6/6). skeptic: recall 1.00 (3/3 found), severity agreement 0.67 (2/3). tracer: recall 1.00 (1/1 found), severity agreement 1.00 (1/1).Recall (threshold 0.50)Severity agreementaccessibility: recall 1.00 (5/5 found), severity agreement 1.00 (5/5)accessibility5/55/5migration: recall 1.00 (5/5 found), severity agreement 0.80 (4/5)migration5/54/5newcomer: recall 1.00 (2/2 found), severity agreement 1.00 (2/2)newcomer2/22/2ops: recall 1.00 (6/6 found), severity agreement 0.50 (3/6)ops6/63/6performance: recall 1.00 (4/4 found), severity agreement 0.50 (2/4)performance4/42/4privacy: recall 1.00 (7/7 found), severity agreement 0.57 (4/7)privacy7/74/7security: recall 1.00 (6/6 found), severity agreement 1.00 (6/6)security6/66/6skeptic: recall 1.00 (3/3 found), severity agreement 0.67 (2/3)skeptic3/32/3tracer: recall 1.00 (1/1 found), severity agreement 1.00 (1/1)tracer1/11/1
Each meter runs from 0 to 1 and ends with its fraction. The dashed line on recall is the threshold; ▲ under marks a role under it. A role without a seeded case has no recall (—).

Every role

The table holds every value the charts draw. Cases: seeded and clean controls; found: seeded defects found over those expected; evidence: the share of checked quotes found at the lines they cite; severity: found defects whose severity is the expected one.

RoleCasesFoundMissesFalse positivesEvidenceSeverityThresholds
accessibility5 (3/2)5/5001.005/5 Met
migration5 (3/2)5/5011.004/5 Met
newcomer3 (2/1)2/2001.002/2 Met
ops5 (3/2)6/6011.003/6 Met
performance5 (3/2)4/4001.002/4 Met
privacy6 (4/2)7/7011.004/7 Met
security6 (4/2)6/6021.006/6 Met
skeptic3 (2/1)3/3041.002/3 Failed: false positives
tracer2 (1/1)1/100—1/1 Met

Planning

25 planning cases replay a request against the repository as it was before an archived change, and score the plan /codev-propose writes against what that change really did: the primary recall is the share of the requirements the request is about that the plan modifies, the collateral recall the share of those the real change modified in passing; a probable duplicate is a requirement added where one should have been modified. Each figure is the median over the repetitions, with its range.

MeasureMedian (range)
Primary recall0.69 (0.58–0.78)
Collateral recall0.39 (0.28–0.44)
Probable duplicates14 (6–15)
Decisions ignored0 (0–1)
Plans that do not validate1 (0–2)

What a run consumes

  • One run of the suite: 55.07 USD
  • Input per call, in tokens: 63465
  • Output per call, in tokens: 696

Every call to the model is recorded. The tokens a call writes to the cache — what entered its context since the previous call, the bulk of a run’s cost — are shared among what brought them in: the skill read, each codev subcommand, the files, the searches, the model’s own output; prompt is Claude Code’s own prompt and the request. Per case the median over its runs, summed over the cases.

Where the tokens goHorizontal bars, one per source, ranked by their share of the cost. skill: 843692 tokens, 23 % of the cost. file: 791139 tokens, 21 % of the cost. prompt: 490778 tokens, 13 % of the cost. edit: 372821 tokens, 10 % of the cost. search: 338245 tokens, 9 % of the cost. shell: 205076 tokens, 6 % of the cost. output: 163212 tokens, 4 % of the cost. codev instructions: 158702 tokens, 4 % of the cost. codev roles: 100208 tokens, 3 % of the cost. codev review: 95800 tokens, 3 % of the cost. codev validate: 64896 tokens, 2 % of the cost. codev new: 54593 tokens, 2 % of the cost. agent: 22404 tokens, 1 % of the cost. codev --help: 2347 tokens, 0 % of the cost. codev list: 507 tokens, 0 % of the cost. codev status: 295 tokens, 0 % of the cost.0 %25 %50 %75 %100 %skill: 843692 tokens, 23 % of the costskill23 %file: 791139 tokens, 21 % of the costfile21 %prompt: 490778 tokens, 13 % of the costprompt13 %edit: 372821 tokens, 10 % of the costedit10 %search: 338245 tokens, 9 % of the costsearch9 %shell: 205076 tokens, 6 % of the costshell6 %output: 163212 tokens, 4 % of the costoutput4 %codev instructions: 158702 tokens, 4 % of the costcodev instructions4 %codev roles: 100208 tokens, 3 % of the costcodev roles3 %codev review: 95800 tokens, 3 % of the costcodev review3 %codev validate: 64896 tokens, 2 % of the costcodev validate2 %codev new: 54593 tokens, 2 % of the costcodev new2 %agent: 22404 tokens, 1 % of the costagent1 %codev --help: 2347 tokens, 0 % of the costcodev --help0 %codev list: 507 tokens, 0 % of the costcodev list0 %codev status: 295 tokens, 0 % of the costcodev status0 %
The share of the cost of the tokens written to the cache, per source, over every case of the suite.
SourceTokensShare of the cost
skill84369223 %
file79113921 %
prompt49077813 %
edit37282110 %
search3382459 %
shell2050766 %
output1632124 %
codev instructions1587024 %
codev roles1002083 %
codev review958003 %
codev validate648962 %
codev new545932 %
agent224041 %
codev –help23470 %
codev list5070 %
codev status2950 %

The thresholds

A role fails when its recall is under 0.50, when it reports more than 2 false positives, or when less than 0.80 of its checked evidence is valid — the suite’s defaults, --min-recall, --max-false-positives and --min-evidence. A role with no seeded case has no recall, and one with no checked finding no evidence validity: neither fails on it.

  • skeptic fails: false positives 4 > 2
  • Within every threshold: accessibility, migration, newcomer, ops, performance, privacy, security, tracer

The limits

  • 5 runs per case. A model does not answer the same way twice: each score is the median of 5 runs of every case, and a change is compared with the range they span, on the same model, not across days or models.
  • Only what the cases cover. 65 cases, 25 of them seeded with 39 defects. A kind of defect that no case seeds is not measured: a recall of 1.00 means these defects were found, not every defect.
  • A controlled context. Each case is a small project reviewed by one role alone, within a fixed budget and time. Your project is larger, and the roles review it together.
  • Not a guarantee. The scores describe the roles on this model and this version of Claude Code. Another model may score differently. Read what the roles report before acting on it.
  • Planning replays a public history. The planning cases replay requests against codev’s own past states, which the model may have read: their figures compare two versions of the skills on the same cases, they do not tell how well codev plans a project it has never seen.

Run it yourself

From a clone of the repository, with Claude Code installed and signed in. A run calls a model: this one cost 276.46 USD for the 5 runs of each case (55.07 USD for one run of the suite).

cargo build --bin codev
cargo run -p codev-evals -- run --out target/evals/mine
cargo run -p codev-evals -- score target/evals/mine

The observations, the reports and the run’s metadata are in evals/baseline. The contributing guide explains how a change to a role is measured.

Concepts

codev keeps three kinds of records in the repository: specs say what the system does, decisions say why it is built the way it is, and changes are the work in progress that modifies both.

_codev/
├── config.yaml     # project configuration
├── specs/          # behavior contracts — WHAT the system does
├── decisions/      # architecture decisions — WHY it is built this way
├── changes/        # work in progress, which modifies the two above
│   ├── <name>/     #   proposal.md, design.md, tasks.md, specs/** (deltas)
│   └── archive/    #   finished changes, dated
├── schemas/        # custom workflow schemas (optional)
└── codev.lock      # pinned inherited git sources (when used)

codev finds this folder by walking up from the current directory, so every command works from any subdirectory of the project.

Capability

A capability is a unit of observable behavior the system offers — user authentication, the theme setting, the validate command. Capabilities are identified by a path of kebab-case segments, such as ui/theme or identity/user-auth, which is also where their spec lives. Group them the way your domain is organized, not the way your code is.

Spec

The main spec of a capability lives at _codev/specs/<capability>/spec.md. It has a ## Purpose — one or two sentences on what the capability is for — and a ## Requirements section:

# Theme Specification

## Purpose

Let users choose the color theme of the interface.

## Requirements

### Requirement: Theme follows the system preference by default

The application SHALL render with the operating system's color scheme until the user picks a theme.

#### Scenario: No theme chosen yet

- **GIVEN** a user who has never changed the theme setting
- **WHEN** their operating system is set to dark mode
- **THEN** the application renders with the dark theme

Each requirement is normative (it uses SHALL or MUST, or DOIT or DOIVENT in a French spec) and has at least one scenario describing observable behavior. A spec describes behavior, never implementation: if the code can change without the behavior changing, the spec should not change either.

You never edit a main spec directly. It changes only when a change is synced or archived, which is what makes its history readable.

Change

A change is a folder _codev/changes/<name>/ that carries one evolution of the system: a proposal, spec deltas, a design and a task list, plus a change.yaml holding its metadata. Which artifacts a change has is defined by its schema; the default spec-driven schema is described in The workflow.

A change is active while it lives in _codev/changes/<name>/. Archiving moves it to _codev/changes/archive/<YYYY-MM-DD>-<name>/, where it becomes a record of why and how the specs changed.

Delta

A delta is the part of a change that modifies a spec. It lives at _codev/changes/<name>/specs/<capability>/spec.md — the same capability path as the main spec it targets — and is organized in up to four operations:

SectionEffect when merged
## ADDED RequirementsAppends the requirements to the main spec
## MODIFIED RequirementsReplaces the requirement of the same name, in place
## REMOVED RequirementsDeletes the requirement, with a Reason and a Migration
## RENAMED RequirementsChanges a requirement’s title, leaving its body untouched

Here is a delta that modifies one requirement and renames another:

## MODIFIED Requirements

### Requirement: Theme follows the system preference by default

The application SHALL render with the operating system's color scheme until the user picks a theme, and SHALL switch live when that preference changes.

#### Scenario: No theme chosen yet

- **GIVEN** a user who has never changed the theme setting
- **WHEN** their operating system is set to dark mode
- **THEN** the application renders with the dark theme

## RENAMED Requirements

- FROM: The chosen theme is remembered
- TO: The chosen theme follows the user

A MODIFIED block replaces the whole requirement, so copy the entire block from the main spec — scenarios included — before editing it. Content you leave out is lost at merge time. If you are adding behavior without changing existing behavior, use ADDED.

The merge touches only the requirements named in the delta. Everything else in the main spec — other requirements, free-form sections, comments — stays as it was.

A delta for a new capability starts with its own ## Purpose; merging it creates the main spec. Removing a capability entirely — a REMOVED delta that empties a spec — requires retire_capabilities: true in change.yaml, because the deletion can only be undone from git.

The exact syntax is in File formats.

Decision

A decision, or ADR (architecture decision record), is a file _codev/decisions/NNNN-<slug>.md that records an architectural choice: its context, the decision, its consequences and the alternatives considered.

codev decision new "Use PostgreSQL for persistence"
codev decision accept 0001

A decision has one of five statuses: accepted, superseded, proposed, deprecated or rejected. Every command that creates a decision — codev decision new, supersede, deviate and promote — creates it proposed, so you can write it freely; codev decision accept makes it accepted once its text is final. Accepting is the only step that makes a decision take effect: a proposed decision supersedes nothing and deviates from nothing yet. A decision is in effect when it is accepted and nothing supersedes it. The decisions in effect are handed to the agent whenever it writes a design.md, so designs follow them instead of re-debating them.

Each decision has a short id (0007) and a qualified id that names its origin: project/0007 for a decision of the project itself, path:~/shared/0100 or git:git@github.com:acme/shared.git/0100 for a decision inherited from another repository.

Seal

An accepted decision is immutable. When a decision becomes accepted through a codev decision command — accept, or new --status accepted — codev records a SHA-256 hash of the decision’s body in _codev/decisions/seal.yaml; codev decision seal does the same for a decision you accepted by hand. codev validate compares the body of every local accepted or superseded decision with its hash, and reports an edit as a decision_seal_mismatch error and a missing seal as a decision_unsealed warning. A proposed decision is not sealed.

The frontmatter is not covered by the seal, so a status can move from accepted to superseded without breaking it.

Note Seal a decision when its text is final: write the proposed decision first, then run codev decision accept <ID>, which sets the status and records the seal in one step. If you have edited a sealed decision on purpose, codev decision seal <ID> --force records the new body; to change what an accepted decision says, supersede it instead.

Supersession

To change a decision, supersede it rather than editing it:

codev decision supersede 0001 "Use SQLite for persistence"

codev creates a new proposed decision whose frontmatter lists supersedes: ["0001"], and leaves 0001 untouched: it stays accepted, and in effect, while you write the new one. Accepting the new decision marks 0001 as superseded in the same step:

codev decision accept 0002

The old body stays exactly as it was, so its seal stays valid and the history of the reasoning is preserved. Only an accepted decision can be superseded: if another decision superseded 0001 in the meantime, codev decision accept refuses with predecessor_not_accepted and writes nothing.

Deviation

An inherited decision cannot be superseded from your project, because you cannot write to its source. Instead, record a local deviation:

codev decision deviate path:~/shared/0100 "Services log in logfmt"

This creates a local proposed decision with deviates_from pointing at the inherited one. The deviation takes effect when you accept it with codev decision accept: the inherited decision then stays visible in codev decision list, but it is no longer in effect for your project and is no longer handed to the agent when writing designs. Until then, the inherited decision is still in effect.

Promotion

A design often contains a decision that deserves to outlive the change. Write it in design.md as a ### Decision: <title> block, then promote it:

codev decision promote add-audit-log "Append-only audit table"

codev creates a proposed ADR whose ## Decision section is the block’s content, verbatim, and replaces the block’s body with a reference to the new ADR. Review it and split the promoted text into the ADR’s sections, then accept it with codev decision accept, which seals it — ideally before archiving the change.

Inherited source

A project can inherit read-only material from other codev repositories — a shared folder on your machine (path:) or a git repository pinned to a commit (git:). Each source contributes its context:, its rules: and its decisions. Nothing executable is ever inherited, and nothing is read from a floating branch: git sources are pinned in _codev/codev.lock. See Inherited sources.

Schema

A schema defines which artifacts a change has, what each one requires, and the instructions and templates the agent follows to write them. codev embeds one schema, spec-driven. A project can define its own in _codev/schemas/. See Custom schemas.

In spec-driven, each instruction opens with the role that owns the artifact and its “Done when” criteria: product owner for the proposal (why and what), QA analyst for the specs (observable behavior), architect for the design (how), tech lead for the tasks (sequencing and verification).

Inherited sources

Teams that maintain several repositories usually share conventions: how services log, which database to use, how APIs are versioned. With inherited sources, those conventions live in one codev repository, and every project that inherits from it receives them — without copying anything.

What a source provides

An inherited source is another codev project, one that has its own _codev/config.yaml. Your project reads three things from it:

  • its context:, prepended to your own context in every artifact’s instructions;
  • its rules:, prepended to your own rules for the same artifact;
  • its decisions, from its _codev/decisions/ folder, which are handed to the agent with yours when it writes a design.md.

Sources are read-only. codev never writes to them, and it only ever reads Markdown and YAML files from them: nothing executable is inherited.

When the agent receives the context and rules, every block carries its origin, ordered from the most general (sources, in declaration order) to the most specific (your project). When two blocks contradict each other, the last one wins, and the skills are instructed to point out the contradiction rather than settle it silently.

Inheritance is not transitive: if a source itself declares inherits:, those sources are ignored and codev warns you. Declare every source you need directly in your project.

Declaring sources at init

The quickest way to start a project on shared conventions is to name the sources when you initialize it, once per --inherit:

codev init --yes --inherit /home/you/acme-standards.git@main
codev initialized in /home/you/acme-api

  Structure   _codev/ — specs, decisions, changes, schemas
  Skills      codev-propose, codev-explore, codev-onboard, codev-apply, codev-sync, codev-archive, codev-update, codev-configure → .claude/skills/
  Inherits    /home/you/acme-standards.git @main → pinned 8dc995327621
…

codev init writes them under inherits: in the new _codev/config.yaml:

# set with codev init --inherit
inherits:
  - git: /home/you/acme-standards.git
    ref: main

A value starting with git@, https://, http://, ssh:// or file://, or ending in .git, is a git source; @<ref> picks the branch or tag, and main is used without it. Anything else is a local folder, which must exist; a relative folder is written as an absolute path, with forward slashes on every platform, so the file reads the same whatever machine ran codev init. A value that is obviously wrong — empty, a missing folder, a git URL ending in @ — is refused with invalid_inherit before anything is written.

Git sources are pinned right away, exactly as codev sources update would. When that fails — no network, missing credentials, a ref that does not exist — the project is still initialized and the source still declared, but left unpinned:

warning: git source `https://git.example.com/acme/codev-standards.git` has no locked SHA — run `codev sources update` to resolve it
warning: the inherited git source(s) could not be pinned: https://git.example.com/acme/codev-standards.git is invalid: ls-remote for `https://git.example.com/acme/codev-standards.git` failed: fatal: unable to access 'https://git.example.com/acme/codev-standards.git/': Could not resolve host: git.example.com
help: run codev sources update

Fix the cause, then run codev sources update. codev init never moves an existing pin and never edits an existing config.yaml: on an initialized project, add sources under inherits: by hand.

Local sources

A path: source is a folder on your machine — typically a clone of your team’s shared repository:

# _codev/config.yaml
inherits:
  - path: ~/src/acme-standards

The path may be absolute or start with ~. It is read directly, so edits in that folder are visible immediately. path: sources are convenient while you author shared conventions; for everyone else, prefer a pinned git source.

Git sources

A git: source is a remote repository, pinned to a commit:

inherits:
  - git: git@github.com:acme/codev-standards.git
    ref: main

ref is required: a branch or a tag. Use subpath when the codev project is in a subfolder of the repository:

inherits:
  - git: git@github.com:acme/platform.git
    ref: v2
    subpath: standards

A git source is used only once it is locked. Resolve and download it with:

codev sources update
Changes:
  + git@github.com:acme/codev-standards.git @main  → 12958274cbed0eb66985f57d3272c6d3134b672d

codev.lock updated.

This resolves each ref to a commit with git ls-remote, fetches that commit into a local cache, and records it in _codev/codev.lock:

version = 1

[[source]]
git = "git@github.com:acme/codev-standards.git"
ref = "main"
commit = "12958274cbed0eb66985f57d3272c6d3134b672d"
resolved_at = "2026-09-30"

Commit codev.lock. Everyone working on the project then reads exactly the same commit, and a change of pin shows up in review like any other diff.

codev sources update and codev init --inherit are the only commands that contact the network, and only codev sources update moves a pin. Every other command reads the locked commit from the cache, offline. Run codev sources update again to move the pins to the current commit of each ref; it reports each source as added (+), moved (~, with the old and new commits) or unchanged (=).

The cache lives in $XDG_CACHE_HOME/codev/, or ~/.cache/codev/ when XDG_CACHE_HOME is not set. Git sources require git on your PATH, with access to the repository — codev uses your existing git credentials.

Inspecting sources

codev sources list
Inherited sources:
  git git@github.com:acme/codev-standards.git  [locked]
      commit: 12958274cbed0eb66985f57d3272c6d3134b672d
      path:   /home/you/.cache/codev/content/12958274cbed0eb66985f57d3272c6d3134b672d

Each source is in one of these states:

StateMeaning
resolvedpath: source found, with a _codev/config.yaml
unreadablepath: source missing, or without a _codev/config.yaml
unlockedgit: source not in codev.lock yet — run codev sources update
lockedgit: source pinned and present in the cache
needs_updategit: source pinned but missing from the cache — run codev sources update

codev sources show <TARGET> shows one source, given by its path or URL, and lists the files it exposes.

Inherited decisions

Inherited decisions appear in codev decision list next to yours. Their qualified id names the source they come from, as declared in your configuration:

path:~/src/acme-standards/0100
git:git@github.com:acme/codev-standards.git/0100

If a local decision has the same short id as an inherited one, the local one wins and codev reports a decision_id_collision warning.

You cannot edit or supersede an inherited decision from your project. When your project must depart from one, record a deviation:

codev decision deviate path:~/src/acme-standards/0100 "Services log in logfmt"

The new local decision references the inherited one in deviates_from. It is created proposed and unsealed: write why your project departs, then accept it, which seals it:

codev decision accept 0003

The deviation takes effect only once accepted. Until then, the inherited decision stays in effect and is still injected into the design instructions. Once the deviation is accepted, the inherited decision stays listed, so the departure is visible, but it is no longer in effect for your project. See Deviation.

What is not inherited

  • Specs. Each project owns its behavior specs.
  • schema, language, workflows and mcp. These belong to the project and to the people working in it.
  • The source’s own sources, as explained above.

Repository integration and codev doctor

Specs and skills are not enough on their own: Claude Code must know that the repository works through codev, CI must catch an invalid spec, and reviewers must see which change a pull request implements. codev init sets these up, codev update keeps them current, and codev doctor tells you what is still missing.

What codev init writes

CLAUDE.md

Claude Code reads CLAUDE.md at the start of every session. codev init creates it, or adds a section to yours, so that Claude does not change behavior without a codev change:

<!-- codev:begin — managed by codev; `codev update` rewrites this block, edit outside it -->
## Spec-driven development with codev

This repository follows spec-driven development with codev.

- `_codev/specs/` describes the current behavior and is authoritative.
- `_codev/decisions/` holds accepted architecture decisions: follow them, do not re-debate them.
- For any change of behavior, start with `/codev-propose`, then implement it with `/codev-apply`. Do not modify behavior without a codev change.
- Trivial fixes (typos, documentation wording) are exempt.
- Run `codev validate` before committing.

Installed skills: `/codev-propose`, `/codev-explore`, `/codev-onboard`, `/codev-apply`, `/codev-sync`, `/codev-archive`, `/codev-update`, `/codev-configure`.
<!-- codev:end -->

The section is in English whatever the language: of the project: it is written for the agent. When /codev-apply is not installed, it asks to implement by following the change’s tasks.md instead.

CI workflow

On a GitHub repository — one with a .github/ folder, or a git remote on github.com — codev init creates .github/workflows/codev.yml:

# codev:managed — generated by `codev init`, refreshed by `codev update`.
# Delete this first line to take the file over: codev will then leave it alone.
name: codev

on:
  push:
  pull_request:

jobs:
  validate:
    name: codev validate
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - name: Install codev 0.6.1
        run: |
          curl -sSL https://raw.githubusercontent.com/mairistem/codev/main/install.sh | CODEV_VERSION=0.6.1 sh
          echo "$HOME/.local/bin" >> "$GITHUB_PATH"
      - name: Validate specs and changes
        run: codev validate --strict

The installer is pinned to the version of codev that wrote the file, so CI validates with the same rules as your machine. codev does not write this file when:

  • another workflow of .github/workflows/ already runs codev validate — any line naming codev then validate counts, such as cargo run --bin codev -- validate;
  • .github/workflows/codev.yml exists and was not written by codev (its first line is not # codev:managed).

codev never edits any other workflow file. On a GitLab repository — a .gitlab-ci.yml file, or a remote on GitLab — it does not touch .gitlab-ci.yml and prints a job to paste instead:

  Repository integration
    + CLAUDE.md                          created
    - .gitlab-ci.yml                     skipped: codev never edits .gitlab-ci.yml — add the job below to run codev validate

        codev:
          image: debian:stable-slim
          before_script:
            - apt-get update -qq && apt-get install -y -qq curl ca-certificates
            - curl -sSL https://raw.githubusercontent.com/mairistem/codev/main/install.sh | CODEV_VERSION=0.6.1 sh
          script:
            - ~/.local/bin/codev validate --strict

    - pull request template              skipped: not a GitHub repository

Elsewhere, the step is skipped with a hint: add codev validate --strict to your pipeline.

Pull request template

On GitHub, codev init adds a section to your pull request template — the first pull_request_template.md found in .github/, the project root or docs/, in any case — or creates .github/PULL_REQUEST_TEMPLATE.md:

<!-- codev:begin — managed by codev; `codev update` rewrites this block, edit outside it -->
## codev

- codev change: <!-- folder under `_codev/changes/`, or "trivial fix, no change" -->
- [ ] `codev validate --strict` passes.
<!-- codev:end -->

Managed sections

codev’s text in CLAUDE.md and the pull request template sits between two HTML comments, invisible once the markdown is rendered:

<!-- codev:begin — managed by codev; `codev update` rewrites this block, edit outside it -->
…
<!-- codev:end -->
  • Everything outside the markers is yours and is never modified. A section added to an existing file goes at its end, after a blank line; you may move the whole block anywhere.
  • codev update rewrites what lies between the markers, and nothing else: edits you make inside the block are lost on the next update.
  • When the markers are unbalanced or repeated, the file is left alone and the managed_section_malformed warning names it.

The workflow file is codev’s as a whole. codev update rewrites it, which moves its pinned version after an upgrade, as long as its first line is # codev:managed. Delete that line to take the file over: codev then leaves it alone.

codev update only refreshes what exists. It never creates CLAUDE.md, the workflow or the template, and never adds a section to a file that has none.

Opting out

FlagSkips
--no-claude-mdthe section in CLAUDE.md
--no-ci.github/workflows/codev.yml
--no-pr-templatethe section in the pull request template
--no-integrationall three

The flags apply to one run of codev init. A later codev init without them writes the files; codev update never does.

codev doctor

codev doctor checks the whole setup and gives, for each gap, the command or skill that closes it. It is read-only and works offline; for the changelog check, it asks the local git repository which changes were archived since the latest tag:

codev doctor
codev doctor — /home/you/acme-app

Configuration
  ✗ config.rules     no rules: in _codev/config.yaml
      fix: /codev-configure
  ✓ config.language  language: is set
  ✓ config.keys      no unknown key in _codev/config.yaml
  ✓ config.roles     active roles: analyst, investigator, product, qa, architect, lead, tracer, skeptic, developer, newcomer; on domain: security (security), privacy (personal-data), accessibility (user-interface), performance (performance), ops (operations), migration (migration); disabled: none
  ✓ skills           8 skill(s) installed and current
  ✓ sources          no inherited git source
  ✓ codev_version    no newer codev release known

Planning
  ✗ specs            no main spec in _codev/specs/
      fix: /codev-propose <a change> — documenting existing behavior is planned work too
  ! decisions        no accepted decision (not every project needs one)
      fix: codev decision new "<title>"
  ✓ validate         codev validate reports no issue

Repository
  ✓ claude_md        CLAUDE.md has the codev section
  ✓ ci               .github/workflows/codev.yml runs codev validate
  ✓ pr_template      the pull request template has the codev section
  ✓ changelog        CHANGELOG.md matches the archived changes

14 check(s), 2 to fix, 1 warning(s)

✗ marks a missing item, ! a warning — a project may legitimately have no accepted decision. The pr_template check only appears for GitHub repositories. The changelog check, a warning only, compares the [Unreleased] section of CHANGELOG.md with what codev changelog generates; the fix is codev changelog --write — see Release notes and CHANGELOG. The codev_version check is missing when the running codev does not satisfy the project’s codev_version, and a warning when the update cache knows a newer release; the fix is codev self-update, or codev self-update --version <X.Y.Z> when the running codev is newer than the requirement allows. The config.keys check warns about keys of _codev/config.yaml this codev does not know — see Unknown keys. The full list of checks is in the CLI reference.

codev init and codev status end with a one-line hint when something is missing, and /codev-onboard lists the missing items with their fix.

In CI, codev doctor --strict exits with status 1 when a check is missing; warnings never fail. codev doctor --json gives the same report to scripts, with stable check ids and codes — see JSON output.

Release notes and CHANGELOG

Every archived change already says why it was made and what changed. codev turns that into release notes: each proposal carries a short ## Release note for end users, and codev changelog assembles the notes of the changes archived since the last release. Choosing the version, tagging and publishing stay with you and your release tooling.

Write the release note with the proposal

/codev-propose writes the section with the rest of the proposal, after ## Impact:

## Release note

- Added: `--format json` on `codev export`.
- Changed: **BREAKING** `codev export` writes to stdout by default; pass
  `--output <PATH>` to write a file.

Each item is - <Category>: <text>, with one of the six categories of Keep a Changelog: Added, Changed, Deprecated, Removed, Fixed, Security. The categories stay in English; the text follows the artifact language. Write for the people who use the product, not for the people who build it. A breaking item starts with **BREAKING**. A change nobody will notice — a refactoring, a test, a CI tweak — writes the single line None.

codev validate checks the section on active changes: a missing section is a warning (release_note_missing), an unknown category, an item without text or an empty section is an error (release_note_invalid). The full format is in File formats.

Generate the notes

codev changelog
## [Unreleased]

### Added

- `--format json` on `codev export`.

### Changed

- **BREAKING** `codev export` writes to stdout by default; pass `--output <PATH>` to write a file.

The range is decided by git: the changes whose folder is in _codev/changes/archive/ now and was not at the latest v* tag. Use --since <ref> and --until <ref> for another range — for instance the notes of a past release:

codev changelog --until v1.4.0 --format markdown

--until v1.4.0 starts after the version tag just below it, v1.3.x. --format markdown drops the version heading, which suits a release body; --format json gives the entries to scripts (see JSON output).

Changes archived before release notes existed have no ## Release note: their What Changes bullets are listed under Changed, and a release_note_missing warning names each of them so you can review the wording. A change whose specs remove requirements without a Removed or BREAKING item gets a release_note_inconsistent warning.

Keep CHANGELOG.md up to date

codev changelog --write

--write puts the [Unreleased] block into CHANGELOG.md, between codev’s markers, right after the file header — the file is created with a standard header if it does not exist:

# Changelog

All notable changes to this project are documented in this file.

<!-- codev:begin — generated by `codev changelog --write` from the archived changes; edit outside this block -->
## [Unreleased]

### Added

- `--format json` on `codev export`.
<!-- codev:end -->

## [1.3.0] - 2026-09-30
…

Released versions, hand-written text and the links at the bottom of the file stay as they are. Running the command again with nothing new leaves the file unchanged. codev doctor reports a changelog warning when the section is behind the archive, or when CHANGELOG.md is missing.

Note If CHANGELOG.md already has a hand-written ## [Unreleased] heading, the first --write takes it over: the managed section replaces that heading, and the entries you wrote below it stay where they are, under the same section.

Release

Right before tagging:

codev changelog --release 1.4.0 --write

The generated block becomes ## [1.4.0] - <today> (or --date YYYY-MM-DD), outside the markers, and a new empty ## [Unreleased] takes its place in the managed section. Commit, then tag v1.4.0 right away: until the tag exists, codev changelog still counts those changes as unreleased.

On GitHub, the release workflow can use the same notes for the release body, built with the codev of the tagged commit:

codev changelog --until "$GITHUB_REF_NAME" --format markdown > release-notes.md

Adopting it in an existing project

If your CHANGELOG.md already describes changes that were archived without a release note, list them under changelog.exclude in _codev/config.yaml, so they are not listed a second time:

changelog:
  exclude:
    - 2026-09-30-legacy-import

Once the next version is tagged, they are out of range and the list can be emptied. See Configuration.

Review record

When the skeptic and the experts challenge a plan, or the newcomer and the experts review the code, what they find is not left in the conversation. It goes to the change’s review record, _codev/changes/<name>/review.md: each finding with its severity, the evidence it rests on, and every answer it received — who fixed it, who disputed it and why, who accepted the risk. codev checks what can be checked, and codev archive will not close a change whose review is not settled.

What a finding holds

## code.review

### security

#### R-security-1 The session lookup concatenates the token

```yaml
severity: high
confidence: high
location: "src/auth/session.rs:42-44"
evidence: |
  let query = format!("SELECT * FROM sessions WHERE token = '{}'", token);
recommendation: Bind the token as a query parameter.
history:
  - status: open
    by: security
```
  • The id, R-security-1, is stable for the life of the change: the role’s id and the next free number. It is never renumbered or reused, so a discussion can cite it.
  • The severity says how bad it is if the reviewer is right, and the confidence how sure the reviewer is — see the scales in Roles. A low-confidence finding is kept and answered, but not shown to you unless you must decide it.
  • The location is path:line or path:start-end from the project root for code, or <file>#<heading> from the change folder for the plan ("design.md#Decision: Sessions live in the database"). Quote it: YAML reads : as a new key.
  • The evidence is the cited text, copied verbatim — whole lines or the fragment that matters. A reviewer proves what it says.

The full format is in File formats.

Isolated reviews

In isolated mode the record also says how the step ran, and who found what:

## code.review

Mode: isolated.
Summarized: src/generated/schema.rs — over the material limit.

### security

#### R-security-1 The session lookup concatenates the token

```yaml
severity: high
confidence: high
location: "src/auth/session.rs:42-44"
evidence: |
  let query = format!("SELECT * FROM sessions WHERE token = '{}'", token);
recommendation: Bind the token as a query parameter.
raised_by: [security, newcomer]
history:
  - status: open
    by: security
```

### newcomer

Fallback: the sub-agent was stopped twice by its time limit.

No finding.
  • Mode: — inline or isolated, under the step’s heading.
  • Summarized: — one line per file the reviewers received as a summary rather than whole, because the material was over its limit.
  • raised_by — when several reviewers found the same defect, the finding is written once, under the role that rated it most severe, and lists every role that raised it, its own first. That role re-checks the answers. A role whose findings were all merged says No finding.; codev review shows it as credited on the shared finding.
  • Fallback: — the role’s sub-agent failed twice and it reviewed inline, in the conversation.

codev validate reports a Mode: other than inline or isolated, a second Mode: or Fallback: line, and a raised_by that is not a list of distinct role ids starting with the finding’s own role (review_invalid). A codev that predates these lines ignores them, and warns about raised_by as an unknown field (review_unknown_field).

The answer loop

A finding starts open. Then:

  1. The author answers. The role that owns the cited artifact at plan.challenge — product owner, QA analyst, architect, tech lead — or the developer at code.review, fixes it (fixed, with ref: the commit or the file change) or disputes it (disputed, with note: the argument).
  2. The reviewer checks the answer, once. A fix is verified (fixed again, by the reviewer) or reopened (open, with why). A dispute is accepted (rejected) or maintained (disputed, with why).
  3. What is left comes to you. The skill’s summary lists, under To decide, every dispute the reviewer maintained and every high-severity finding still open, with both arguments. You fix it, accept the risk (accepted-risk, with a justification) or defer it (deferred, with to: the change or the issue it goes to). The skill records your decision as by: human:<your name>; it never decides for you.
StatusSet byRequires
openthe reviewer (first entry, or a fix that does not hold)note when it reopens a fix
fixedthe author, then the reviewer to verify itref
disputedthe author, or the reviewer maintaining itnote
rejectedthe reviewer, or a human, after a dispute—
accepted-riska humannote: the justification
deferredthe author, or a human for a high findingto

accepted-risk, deferred and rejected are final: to revisit one, raise a new finding.

What codev checks

codev validate reads the record of every active change. It never judges a finding — an open finding is the normal state of a review — but it checks everything that needs no judgement:

  • The format: the headings, one yaml block per finding, the fields, the ids, the locations (review_invalid), and an unknown field (review_unknown_field, a warning).
  • The history: the first entry is open by the finding’s role, each transition is in the table above (review_invalid), and each entry carries what its status requires, decided by whom it must be (review_decision_incomplete).
  • The evidence, for open, disputed, accepted-risk and deferred findings, against the files as they are now: the file, the line or the heading exists (review_location_missing); each quoted line is found in consecutive lines of the file, whitespace and line endings ignored, starting no more than 5 lines from the cited ones (review_evidence_not_found, or review_evidence_moved when it is further away). A fixed or rejected finding is not compared: its code was meant to change. A file that is not UTF-8 text, holds NUL bytes or is larger than 4 MiB is not compared (review_evidence_unchecked).
  • The sections: when the record holds a step, every role active at it for the change has its section (review_role_missing). A role turned off may say Disabled by configuration..

No check uses git or the network: they read the working tree.

codev review

codev review --change add-sessions

Shows the record step by step — each role, each finding with its severity, status and location —, who must act next on each one (author, reviewer or human), the record’s defects, and whether the review lets the change be archived. The skills read this printed output to resume an interrupted review and to check the record; --json gives the ReviewV1 document, for scripts. It exits with 1 only when the record has an error.

Archiving

codev archive checks the review after validation. It refuses, with the code review_blocked, when:

  • roles were active at plan.challenge or code.review and the record does not exist (review_record_missing), or has no section for that step (review_step_missing);
  • a high finding is still open or disputed (review_unresolved);
  • the record comes from a newer codev (review_format_unsupported).

A step with no active role needs no section. codev sync does not look at the record.

Changes started before the record

A change planned with an earlier codev has no record, so archiving it is refused. Either run the review steps again — /codev-apply reviews the code and writes the record — or say explicitly that the change was not reviewed by turning its review roles off in its change.yaml:

roles:
  skeptic: never
  newcomer: never

A team that does not use the skills at all sets the same in _codev/config.yaml. To keep everyone on a codev that enforces the gate, raise codev_version to the release that ships it: an older codev ignores review.md and archives anyway.

Edge cases

  • Re-running a step adds to the record; a finding already recorded is not raised again, and a step or a role written twice is an error.
  • An interrupted session resumes from the record: awaiting says who must answer next.
  • A docs-only change, or one with no code yet, still has its review sections — No finding. is a valid answer.
  • Generated, vendored or binary files can be cited; binary and very large files are not compared.
  • Windows: \ in a location reads as /, and \r\n line endings are ignored in the record and in the cited files.
  • Monorepos: paths are relative to the codev project root; a file outside it cannot be cited.

Jira and other MCP servers

codev’s skills can pull context from external systems through the MCP servers connected to your Claude Code session. The CLI itself never talks to them: the skills detect what they need in your request and call the MCP tool directly.

Today, one integration is available: /codev-propose reads a Jira ticket.

Jira

When your request to /codev-propose contains a ticket identifier — anything matching [A-Z]{2,}-\d+, such as PROJ-123 — and a Jira MCP tool is configured, the skill:

  1. calls the configured tool once, for the first identifier it found;

  2. uses the ticket’s title, description, status and type as context for the plan;

  3. cites the ticket at the top of the proposal:

    # Proposal: Add dark mode
    
    > Source: ticket **PROJ-123** — "Dark mode for the dashboard" (In Progress)
    
    ## Why
    

The integration is strictly read-only: one call to the one configured tool, never a search, a comment or a transition. If the request mentions several tickets, only the first is fetched; the others are listed under the citation for traceability.

If a ticket is mentioned but the MCP server is not available in the session, the skill says so, writes the proposal from your request alone, and cites the ticket as “content not retrieved”.

Configuration

The name of the Jira tool depends on how the MCP server is registered in your Claude Code setup, so it is configured per project:

# _codev/config.yaml
mcp:
  jira_tool: mcp__atlassian__getJiraIssue

codev init fills it in for you when it finds a server whose name, command or URL mentions Jira or Atlassian in .mcp.json, .claude/settings.json or ~/.claude.json:

  ✓ Jira MCP detected: mcp__atlassian__getJiraIssue
    (source: .mcp.json → server "atlassian")

The tool name follows Claude Code’s convention, mcp__<server name>__getJiraIssue, with spaces and dots in the server name replaced by underscores — for example, a connector named claude.ai Atlassian Rovo gives mcp__claude_ai_Atlassian_Rovo__getJiraIssue. If yours differs, look for the exact name in the tool list of a Claude Code session and set it by hand.

At install time, codev adds the tool to the allowed-tools of codev-propose, so the skill may call it and nothing else from that server. After changing mcp:, regenerate the skills:

codev update --force

Without mcp.jira_tool, ticket detection is inert: the skill behaves exactly as it does in a project without any MCP integration.

Note mcp: is never inherited from an inherited source: tool names depend on each person’s Claude Code setup, not on a shared repository.

Adding another MCP integration

MCP integrations are part of codev itself: each one is a configuration key and a placeholder in a workflow, so adding one — for example a Confluence page or a design tool — is a contribution to codev rather than a setting. The pattern is the same as for Jira:

  1. Add a key under mcp: in the project configuration (crates/codev-engine/src/config.rs).
  2. Carry it into the skill render context and substitute a placeholder such as {{JIRA_MCP_TOOL}} in both the allowed-tools and the body of the workflow that uses it (crates/codev-agents/src/claude.rs).
  3. Describe the detection and the call in the workflow file under assets/workflows/, with a clean fallback when the key is absent.

The existing skill is extended rather than duplicated: there is one /codev-propose, whatever the source of the request. See CONTRIBUTING.md to propose one.

Artifact language

codev itself speaks English: its commands, messages, skills and templates are in English. The planning artifacts your team reads and approves — proposals, specs, designs, tasks — can be written in any language.

Setting the language

The language: key of _codev/config.yaml sets the language of the prose in artifacts, as an ISO 639 code:

language: fr

Accepted values are a two- or three-letter lowercase language code, optionally followed by one subtag such as a region or a script: en, fr, de, pt-BR, zh-Hant. Any other value makes the configuration invalid. When the key is absent, the language is English (en).

How codev init chooses it

codev init writes the language: key for you, with a comment saying where the value came from. It uses, in order:

  1. the --language <CODE> option;
  2. otherwise your locale — the first of LC_ALL, LC_MESSAGES and LANG that names a language. C and POSIX are skipped, so LC_ALL=C does not hide a meaningful LANG;
  3. otherwise en.
codev init --language pt-BR
# set with `codev init --language`
language: pt-BR

Detection keeps only the language part of the locale — fr_FR.UTF-8 gives fr — except where the region changes the written language: pt_BR gives pt-BR, zh_TW and zh_HK give zh-Hant, zh_CN and zh_SG give zh-Hans. Pass --language to record any other region. --no-detect disables locale detection along with the rest of the environment probe.

On a project that already has a _codev/config.yaml, codev init does not touch the file. To change the language later, edit the key.

What is translated, and what is not

The skills write every sentence in the configured language, whatever language you chat with Claude in: the files are the team’s record, and the language is the team’s choice.

The skills write the structure of the files in English: template headings (# Proposal:, ## Why, ## What Changes, ## Context, # Tasks…), spec and delta structure (## Purpose, ### Requirement:, #### Scenario:…), and the scenario and normative keywords (**WHEN**, **THEN**, SHALL, MUST).

codev reads that structure in English or in French, whatever language: says, so a team can also write its specs entirely in French. Each keyword has its text in every language of codev’s keyword catalog:

EnglishFrench
## Purpose## Objet
## Requirements## Exigences
### Requirement:### Exigence :
#### Scenario:#### Scénario :
## ADDED Requirements## Exigences AJOUTÉES
## MODIFIED Requirements## Exigences MODIFIÉES
## REMOVED Requirements## Exigences SUPPRIMÉES
## RENAMED Requirements## Exigences RENOMMÉES
**Reason**, **Migration****Raison**, **Migration**
FROM: / TO:DE : / VERS :
SHALL, MUSTDOIT, DOIVENT
## What Changes## Changements
## Domains, None## Domaines, Aucun
## Release note, None## Note de version, Aucune
Added, Changed, Deprecated, Removed, Fixed, SecurityAjouté, Modifié, Obsolète, Supprimé, Corrigé, Sécurité
## Decisions, ### Decision:## Décisions, ### Décision :

A requirement written entirely in French therefore looks like this:

### Exigence : Le thème suit la préférence du système

L'application DOIT s'afficher avec le thème du système tant que l'utilisateur n'en a pas choisi.

#### Scénario : Aucun thème choisi

- **GIVEN** un utilisateur qui n'a jamais modifié le thème
- **WHEN** son système est en mode sombre
- **THEN** l'application s'affiche avec le thème sombre

How codev reads and writes them:

  • French keywords forgive case, accents and the space — ordinary or no-break — before a colon: ### Exigence: X and #### Scenario : Y are read too. English keywords are read exactly as before.
  • Normative keywords count only in upper case, in both languages: doit in lower case is ordinary prose, and the requirement fails validation.
  • A document may mix both languages.
  • When codev sync or codev archive edits a spec, it writes the keywords in that spec’s language; a new spec takes the language of the delta that creates it.
  • The changelog shows release note categories in English, whatever language wrote them.
  • Domain names (security, migration…) and the review record’s markers stay in English. codev does not read the **GIVEN** / **WHEN** / **THEN** lines, which the skills write in English.

Warning A codev release older than this catalog rejects French keywords. Before your team writes them, raise codev_version in _codev/config.yaml to the first release whose changelog announces them, so that every contributor runs a codev that reads them. A heading in a language codev does not know, such as ### Requisito:, is reported in a delta section (delta_unexpected_heading), and the sync and the archive refuse the change.

Which skills use it

codev instructions --json exposes the language in its language field. /codev-propose and /codev-update write artifact prose in that language, and /codev-configure writes the context: and rules: it proposes in it too. The ADR template used by codev decision commands has English section headings; write the body in your team’s language.

Custom schemas

A schema defines the planning workflow of a change: which artifacts it has, which ones depend on which, and the instruction and template the agent follows for each. codev embeds one schema, spec-driven — proposal, specs, design, tasks — which suits most projects. When it does not, you can define your own, as plain data files: no code, no rebuild.

Where schemas live

A project schema is a folder under _codev/schemas/:

_codev/schemas/
└── lite/
    ├── schema.yaml
    └── templates/
        ├── brief.md
        ├── spec.md
        └── tasks.md

codev schemas lists what is available:

Available schemas:
  lite (project)
    brief → specs → tasks
  spec-driven (built-in)
    proposal → specs → design → tasks

A project schema named spec-driven replaces the built-in one, without changing anything else.

A schema’s name is its folder: --schema lite, schema: lite and change.yaml all refer to _codev/schemas/lite/. Keep the name: inside schema.yaml equal to the folder; when it differs, codev still uses the folder name and codev schemas reports a warning schema_name_mismatch.

Writing a schema

# _codev/schemas/lite/schema.yaml
name: lite
description: Small changes — a short brief, spec deltas and a task list
artifacts:
  - id: brief
    generates: brief.md
    description: What changes, and why
    template: brief.md
    instruction: |
      Explain in a few sentences what changes and why.
  - id: specs
    generates: "specs/**/*.md"
    description: Spec deltas
    template: spec.md
    requires: [brief]
  - id: tasks
    generates: tasks.md
    template: tasks.md
    requires: [specs]
apply:
  requires: [tasks]
  tracks: tasks.md
KeyRequiredMeaning
nameyesSchema name, in kebab-case — the name of the schema’s folder, which is what codev uses
versionnoSchema format version, 1 by default
descriptionnoOne-line description
artifactsyesThe artifacts of a change, at least one
artifacts[].idyesArtifact id, in kebab-case, unique
artifacts[].generatesyesOutput path relative to the change folder; may be a glob such as specs/**/*.md
artifacts[].descriptionnoShort description, shown to the agent
artifacts[].templatenoTemplate file name, looked up in the schema’s templates/ folder
artifacts[].instructionnoGuidance for the agent writing this artifact
artifacts[].requiresnoIds of the artifacts that must exist first
artifacts[].rolenoThe role that owns the artifact — see Declaring artifact roles
apply.requiresyesArtifacts that must exist before implementation starts
apply.tracksyesThe file whose checkboxes track implementation progress
apply.instructionnoGuidance for the implementation phase

Unknown keys are rejected, so a typo cannot silently produce a workflow that behaves differently from what you wrote. codev also rejects a schema whose dependencies reference a missing artifact or form a cycle, and names the artifacts involved. codev schemas still lists the other schemas, and reports the refused one as a warning schema_unusable with the reason.

An artifact is done when its file exists — or, for a glob, when at least one file matches. It is ready when all the artifacts it requires are done.

Declaring artifact roles

An artifact may declare the role that owns it. The agent receives it in the role field of codev instructions and checks its criteria before moving on; codev roles --at plan.write lists it.

  - id: brief
    generates: brief.md
    role:
      id: editor
      name: { en: Editor, fr: Rédacteur }
      question: Is the brief clear?
      done_when:
        - One page at most
        - The why comes first
KeyRequiredMeaning
role.idyesRole id, in kebab-case, unique in the schema, and not a built-in step role such as skeptic
role.nameyesDisplay names by language code; en is required and serves the languages without a name
role.questionyesThe question the role owns
role.done_whennoThe criteria the agent checks, with the origin schema:<name>

A project extends the criteria under roles: with the role’s id; an artifact role cannot be disabled. An artifact without role: has none, and its instruction is used as written.

Using a schema

Choose a schema per change:

codev new change quick-fix --schema lite

or make it the project default in _codev/config.yaml:

schema: lite

The schema is recorded in each change’s change.yaml, under its folder name, so changing the default does not affect changes already in progress.

The skills work with any schema: /codev-propose writes whatever artifacts are ready, in dependency order, using codev instructions. Per-artifact rules: in the configuration are keyed by artifact id, so rules written for brief apply to the brief artifact of the lite schema.

Behaviors tied to conventions

A few behaviors rely on conventions rather than configuration. Keep them in mind when you design a schema:

  • Spec deltas are files under specs/. Validation, sync and archive read deltas from specs/ in the change folder. An artifact that writes elsewhere is not merged into the main specs.
  • skip_specs: true skips every artifact whose generates starts with specs/, whatever its id.
  • Decisions are injected into the artifact whose id is design. Name your design artifact design if you want the agent to receive the decisions in effect while writing it.

Command-line interface

This chapter documents every codev command. The help text of each command is reproduced exactly as codev <command> --help prints it; run that command to see the help of the version you have installed.

codev --help
codev adds a thin layer of specs to a repository so that you and your agent agree on what must be built before a single line of code is written.

The commands below run in your terminal. The workflows are invoked in the Claude Code chat: /codev-propose, /codev-explore.

Usage: codev <COMMAND>

Commands:
  init          Initialize codev in a project and install the Claude Code skills
  update        Regenerate the skills, and refresh codev's managed sections, after a codev upgrade
  self-update   Download and install the latest codev release, verified
  doctor        Check what the project's codev setup still lacks, and how to fix it
  new           Create a new item
  list          List active changes, or specified capabilities with --specs
  search        Search the requirements and decisions that match a query
  show          Print one requirement, or the requirement names of a capability
  status        Show the state of a change's artifacts
  instructions  Print everything needed to write an artifact
  roles         List the roles active at a workflow step, with their criteria
  schemas       List the available workflow schemas
  decision      Create, accept, inspect and supersede architecture decisions
  sources       Manage inherited sources (local paths and remote git repositories)
  sync          Merge a change's deltas into the main specs without archiving
  review        Show a change's review record and what is left to decide
  archive       Merge, then move a change to the dated archive
  changelog     Generate release notes from the archived changes
  docs          Open the codev documentation in the browser
  completions   Generate a shell completion script for local installation
  validate      Check changes and specs for structural errors and consistency
  help          Print this message or the help of the given subcommand(s)

Options:
  -h, --help
          Print help (see a summary with '-h')

  -V, --version
          Print version

Conventions

These rules hold for every command except docs and completions, which do not read the project:

  • Project discovery. codev looks for _codev/ in the current directory, then in each parent directory. Run commands from anywhere inside the project. Outside a project, commands fail with no_codev_root.
  • --json. Every command that reads or writes the project accepts --json. stdout then carries exactly one JSON document — on failure too — and human messages are not printed. See JSON output.
  • Exit status. 0 on success, 1 on failure. For codev validate, see its section.
  • Errors. In human mode, errors go to stderr as error: …, often followed by a help: … line with the fix.
  • Choosing a change. Commands that take --change <CHANGE> infer it when the project has exactly one active change, and fail with ambiguous_change when there are several.

Project

codev init

Initialize codev in a project and install the Claude Code skills

Usage: codev init [OPTIONS] [PATH]

Arguments:
  [PATH]
          Project folder (default: the current folder)

Options:
      --force
          Rewrite skills even if they were edited by hand

  -y, --yes
          Accept all defaults without prompting (defaults + detected values)

      --no-detect
          Disable the environment probe (useful for reproducible tests)

      --preset <PRESET>
          Preselect the answer to the workflows question

          Possible values:
          - full:    All 8 workflows
          - minimal: propose, explore, onboard, configure
          - custom:  Pick the workflows one by one

      --language <CODE>
          Language of the prose skills write in artifacts, as an ISO 639 code (`en`, `fr`, `pt-BR`…). Default: detected from the locale, otherwise `en`

      --inherit <SOURCE>
          Inherit conventions from a source, written under `inherits:` (repeatable). A git URL (`git@…`, `https://…`, `ssh://…`, `file://…`, or ending in `.git`), optionally suffixed with `@<ref>` (default `main`), or a local folder. Git sources are pinned in `_codev/codev.lock` right away

      --no-claude-md
          Do not write codev's section in `CLAUDE.md`

      --no-ci
          Do not write `.github/workflows/codev.yml`

      --no-pr-template
          Do not write codev's section in the pull request template

      --no-integration
          Skip all repository integration: same as `--no-claude-md --no-ci --no-pr-template`

      --json


  -h, --help
          Print help (see a summary with '-h')

Initializes codev in PATH (the current folder by default): creates the _codev/ tree, writes _codev/config.yaml, and installs the skills into .claude/skills/. See What codev init does for the probe and the questions.

  • --yes skips every question and applies the defaults and detected values. Without a terminal on stdin (CI, pipes), --yes is implied.
  • --preset answers the workflows question: full installs all eight workflows, minimal installs propose, explore, onboard and configure, custom lets you pick them one by one (and falls back to full without a terminal).
  • --language sets the language: key. Without it, the language comes from the locale, else en. See Artifact language.
  • --no-detect disables the probe of manifests, license, CI, locale and MCP servers.
  • --inherit <SOURCE> declares an inherited source under inherits:, once per source. A value starting with git@, https://, http://, ssh:// or file://, or ending in .git, is a git source; an @<ref> suffix picks the branch or tag (…/conventions.git@v2), main otherwise. Anything else is a local folder, which must exist; a relative path is written as an absolute one. Git sources are pinned in _codev/codev.lock right away, as codev sources update would; if that fails (network, credentials, unknown ref), init still succeeds, warns with inherit_pin_failed and prints help: run codev sources update. An invalid value fails with invalid_inherit before anything is written. See Inherited sources.
  • --no-claude-md, --no-ci and --no-pr-template skip one integration file each; --no-integration skips all three. See Repository integration and codev doctor.

Unless you opt out, codev init also writes codev’s section in CLAUDE.md and, on GitHub, .github/workflows/codev.yml and a section in the pull request template. The summary lists each file as created, appended, refreshed, up to date or skipped, with the reason; for a GitLab repository it prints a job to paste into .gitlab-ci.yml, which codev never edits. The last line suggests codev doctor when something is still missing.

When _codev/config.yaml already exists, it is left untouched: codev init only creates missing folders, installs or refreshes the skills, and adds or refreshes the integration files. --inherit sources are then not written; the inherit_not_written warning names them so you can add them by hand. Skills you edited by hand are preserved unless you pass --force.

codev update

Regenerate the skills, and refresh codev's managed sections, after a codev upgrade

Usage: codev update [OPTIONS]

Options:
      --force  Rewrite skills even if they were edited by hand
      --json
  -h, --help   Print help

Regenerates the skills listed by workflows: in the configuration (all eight when the key is absent), for example after upgrading codev or changing the mcp: configuration. codev update rewrites a skill stamped with another version; among the skills stamped with its own version, it rewrites one whose content still hashes to its checksum — codev’s rendering, from an earlier build or for the other review mode — and preserves one that no longer does, edited by hand, unless you pass --force. A skill without a checksum, rendered before checksums existed, is preserved when it carries this version’s stamp and differs from the rendering by more than the review mode: run codev update --force once to bring such skills under the checksum — it also overwrites a skill you really edited, so check git diff first and apply your edits again after. A preserved skill is reported. Skills removed from workflows: are not deleted. An unknown workflow name is ignored with a warning unknown_workflow. Missing _codev/ folders and a missing _codev/config.yaml are recreated; existing files are never overwritten.

codev update also refreshes codev’s managed sections in CLAUDE.md and the pull request template, and .github/workflows/codev.yml when its first line is # codev:managed — which moves its pinned version to the running one. It only refreshes what exists: it never creates these files nor adds a section, so a project initialized with --no-integration stays as it is.

codev self-update

Download and install the latest codev release, verified

Downloads the release archive for this platform from GitHub, verifies its SHA-256 against the release's `SHA256SUMS`, replaces this binary atomically, then runs the new binary's `codev update` in the current project, if any. Never downgrades unless `--version` asks for it. A binary installed by cargo, a cargo build or a package manager is left alone: the command that upgrades it is printed instead.

Usage: codev self-update [OPTIONS]

Options:
      --version <X.Y.Z>
          Install this version (`X.Y.Z`) instead of the latest; allows a downgrade

      --check
          Only report the running and latest versions (exit code 0 whether or not an update is available)

      --snooze
          Silence the update notice for the latest known version, for 7 days

  -y, --yes
          Do not ask for confirmation

      --json
          JSON output; implies `--yes`

  -h, --help
          Print help (see a summary with '-h')

Installs a newer codev in place of the running one, in one command and never behind your back:

  1. resolves the target — --version, or the latest release, asked to GitHub now whatever the cache, CI or CODEV_NO_UPDATE_CHECK;
  2. on a terminal, asks for confirmation unless --yes is given;
  3. downloads codev-<version>-<target>.tar.gz (.zip on Windows) and SHA256SUMS from the GitHub release, and verifies the archive’s SHA-256;
  4. writes the new binary next to the running one, then renames it into place, so the binary’s path always holds a complete binary;
  5. inside a codev project, runs the new binary’s codev update.

A binary installed by cargo install, built in a cargo target/ folder, or installed by a package manager (Homebrew, Nix, Scoop, /usr/bin) is left alone: the command that upgrades it is printed and the exit status is 0. The latest release older than the running binary is refused (update_downgrade_refused) unless you ask for it with --version.

--check prints the running and latest versions, refreshes the update cache and exits with 0 whether or not an update is available. --snooze silences the update notice of codev status and of the skills for the latest known version, for 7 days; a newer release is announced again.

CodeMeaning
update_check_failedThe release API cannot be reached, or answers no release
update_unsupported_platformNo published binary for this platform; build from source
update_download_failedThe archive or SHA256SUMS cannot be downloaded
update_checksum_mismatchSHA256SUMS has no entry for the archive, or its SHA-256 differs
update_extract_failedThe archive cannot be extracted, or holds no codev binary
update_not_writableThe binary’s folder cannot be written
update_downgrade_refusedThe target is older than the running version, without --version
invalid_version--version is not X.Y.Z

Every failure leaves the installed binary untouched. When codev update fails in the project after a successful update, the command warns update_project_refresh_failed and still exits with 0: run codev update there. For --json, see JSON output.

codev doctor

Check what the project's codev setup still lacks, and how to fix it

Read-only and offline: configuration, skills, inherited sources, the running codev version against `codev_version` and the cached update check, specs, decisions, `CLAUDE.md`, CI and pull request template, `codev validate`, and whether `CHANGELOG.md` matches the archived changes. Each check is ok, missing or a warning, with the command or skill that fixes it.

Usage: codev doctor [OPTIONS]

Options:
      --strict
          Exit with code 1 when a check is missing (warnings never fail)

      --json


  -h, --help
          Print help (see a summary with '-h')

Lists what the project’s codev setup still lacks, grouped under Configuration, Planning and Repository, with the command or skill that fixes each item. It writes nothing and needs no network; the changelog check runs local, read-only git queries.

CheckPasses whenFix
config.rulesrules: has at least one entry, inherited ones included/codev-configure
config.languagelanguage: is setadd language: <code>
config.keys_codev/config.yaml has no key this codev ignores — a warning onlycorrect or remove the key, or codev self-update
config.rolesevery entry of roles: is valid — informational, it lists the active roles, the roles active on domain with their domains, and the disabled ones; a warning roles_invalid otherwisecodev validate
skillsevery configured skill is installed and generated by this codev versioncodev update
sourcesevery git source is pinned in codev.lock and cachedcodev sources update
codev_versionthe running codev satisfies codev_version, and the cached update check knows no newer release — a warning only for the lattercodev self-update, or codev self-update --version <X.Y.Z> when the running codev is above the requirement
specsat least one main spec exists/codev-propose
decisionsat least one decision is accepted — a warning onlycodev decision new
validatecodev validate reports nothingcodev validate
claude_mdCLAUDE.md has the codev sectioncodev init
cia GitHub workflow or .gitlab-ci.yml runs codev validatecodev init on GitHub
pr_templatethe pull request template has the codev section — GitHub onlycodev init
changelogCHANGELOG.md matches what codev changelog generates — a warning onlycodev changelog --write

The codev_version check reads the update cache that codev status keeps; it never contacts the network.

Each line shows ✓ (ok), ✗ (missing) or ! (warning); the last line counts the checks and those left to fix. The exit status is 0, unless --strict is given and a check is missing: warnings never fail. See Repository integration and codev doctor and, for --json, JSON output.

codev docs

Open the codev documentation in the browser

Three forms:

- default: writes `codev-docs-<version>.html` to the system temp folder and opens it in the browser; - `--write <PATH>`: writes the HTML to the given path, opens nothing (for sharing — email, Confluence, shared drive); - `--print`: prints the markdown source to stdout (to pipe into `less`, `bat` or an LLM).

Usage: codev docs [OPTIONS]

Options:
      --print
          Print the markdown source to stdout (does not open anything)

      --write <PATH>
          Write the HTML to the given path (does not open anything)

      --lang <LANG>
          Language of the documentation

          Possible values:
          - en: English
          - fr: French

          [default: en]

  -h, --help
          Print help (see a summary with '-h')

Renders this documentation as one self-contained HTML page — inline CSS, no network access — and opens it in your browser. The page is written to codev-docs-<version>.html in the system temporary folder. --write writes it elsewhere without opening it, for sharing; --print prints the Markdown source. --lang selects the English (en, the default) or French (fr) edition. codev docs works anywhere, including outside a codev project.

--print is meant to be piped: when the reader stops early, as in codev docs --print | head, the command stops silently and exits with code 0. On the page, notes and warnings keep their meaning: a note has a green rule, a warning a coral one.

codev docs --lang fr --write ~/Downloads/codev-manual-fr.html

codev completions

Generate a shell completion script for local installation

The output goes to stdout — redirect it to your shell's completions folder. Typical setups:

- bash: `codev completions bash > ~/.local/share/bash-completion/completions/codev` - zsh: `codev completions zsh > "${fpath[1]}/_codev"`, then `compinit` - fish: `codev completions fish > ~/.config/fish/completions/codev.fish` - powershell: `codev completions powershell | Out-String | Invoke-Expression`

The command touches no file; it does not read `_codev/` either and works in any directory.

Usage: codev completions <SHELL>

Arguments:
  <SHELL>
          Target shell: bash, zsh, fish, powershell, elvish

          [possible values: bash, elvish, fish, powershell, zsh]

Options:
  -h, --help
          Print help (see a summary with '-h')

See Shell completions.

Changes

codev new change

Create a change

Usage: codev new change [OPTIONS] <NAME>

Arguments:
  <NAME>  Name in kebab-case (`add-user-auth`)

Options:
      --schema <SCHEMA>  Workflow schema to use
      --goal <GOAL>      Goal, kept in the change's metadata
      --json
  -h, --help             Print help

Creates _codev/changes/<NAME>/ with a change.yaml recording the schema, the creation date and the goal, when one is given. The name must be kebab-case: lowercase letters, digits and single hyphens, neither leading nor trailing; it may start with a digit. archive is reserved for the folder of archived changes and refused. The schema defaults to the schema: key of the configuration, else spec-driven; change.yaml records the name the schema was found by — the folder name of a project schema. Fails, writing nothing, with invalid_change_id — naming the rule the name breaks — with change_exists if the change already exists, and with schema_not_found if the schema does not exist.

codev new change add-dark-mode --goal "Let users switch the UI to a dark theme"

codev list

List active changes, or specified capabilities with --specs

Usage: codev list [OPTIONS]

Options:
      --specs
      --json
  -h, --help   Print help

Lists the active changes, or with --specs the capabilities that have a main spec: each folder under _codev/specs/ holding a file named exactly spec.md, nested folders included. Other files, such as a README.md or notes/myspec.md, are not specs and are ignored, by codev validate as well.

Search the requirements and decisions that match a query

Usage: codev search [OPTIONS] <QUERY>...

Arguments:
  <QUERY>...  Words naming the behavior, in the language the specs are written in

Options:
      --limit <LIMIT>  Results to print, from 1 to 50 [default: 10]
      --archive        Also list the matching archived changes, in a section of their own
      --json
  -h, --help           Print help

Ranks the requirements of the main specs — each with its description and scenarios — and the decisions, inherited ones included, by how well they match the query, and prints the best ones: kind, identifier (<capability>::<requirement>, or the decision’s id and title with its status and whether it is in effect) and an excerpt. Case, accents and common words are ignored, and words match through their stem in the language the specs are written in: write the query in that language, so decisions finds decision. The output holds 10 results unless --limit asks for 1 to 50, whatever the project’s size. --archive adds the matching archived changes in a section of their own, never ranked with the requirements. A query that matches nothing says so and exits with 0; a query of common words only fails with search_query_empty, and a --limit out of range with search_limit_invalid. The command only reads.

codev search create a decision from the command line
codev search "decision seal" --archive

codev show

Print one requirement, or the requirement names of a capability

Usage: codev show [OPTIONS] <TARGET>

Arguments:
  <TARGET>  `<capability>::<requirement name>`, or `<capability>` for its index

Options:
      --json
  -h, --help  Print help

codev show <capability>::<requirement name> prints that requirement as its main spec holds it — heading, description and scenarios, verbatim — and nothing else of the spec; the name is compared ignoring case and spacing. codev show <capability> prints the capability’s purpose and its requirement names, in the <capability>::<name> form the command accepts. The capability must be one of those codev list --specs names: anything else fails with unknown_capability, and a requirement the capability does not hold with unknown_requirement, which lists the ones it does.

codev show decisions
codev show "decisions::Creating a decision through the CLI"

codev status

Show the state of a change's artifacts

Usage: codev status [OPTIONS]

Options:
      --change <CHANGE>  Change name (inferred when there is only one)
      --json
  -h, --help             Print help

Shows the state of each artifact of a change — done [x], ready [ ], blocked [-] with the artifacts it waits on, or skipped [~] — then Planning: <n>/<total> artifacts and the next artifact to write, or Planning is complete.. Fails with no_active_change when the project has no active change. In both cases, when codev doctor would report a missing check, a last hint: line on stderr suggests running it. A --change naming a change that does not exist fails with unknown_change; --change archive fails with invalid_change_id, since that name is reserved for the archived changes.

When a newer codev release is known and you have not snoozed it, stderr also carries codev X.Y.Z is available (you have A.B.C) — run `codev self-update` . To know, codev status asks GitHub for the latest release at most once every 24 hours, with a 2-second timeout, and caches the answer in ~/.cache/codev/update-check.json. It never checks when CI is set or with CODEV_NO_UPDATE_CHECK=1, and a failed check is silent. No other command checks. With --json, the same information is in the update object — see JSON output.

codev instructions

Print everything needed to write an artifact

Usage: codev instructions [OPTIONS] [ARTIFACT]

Arguments:
  [ARTIFACT]  Artifact identifier (default: the next one to write)

Options:
      --change <CHANGE>
      --json
  -h, --help             Print help

Prints everything an agent needs to write one artifact: where to write it, the schema’s instruction, the template, the artifact language, the project context and rules with their origin, the dependencies to read first, and what the artifact unlocks. For the design artifact, it also lists the architecture decisions in effect, and the artifact’s role with its criteria. Without ARTIFACT, it picks the first artifact that is ready to write. It writes no file.

Once the change’s proposal is written, the instructions of the artifacts that require it directly — specs and design — also list the existing requirements the change likely touches, ranked against the proposal’s Why and What Changes, at most 10, each with an excerpt, and say that one is read with codev show <capability>::<requirement> and that a requirement the change alters is modified rather than added again. A spec that cannot be read is left out with a warning spec_unreadable.

For an artifact disabled by skip_specs, it says the artifact must not be created, with a warning artifact_skipped. It fails with unknown_artifact when ARTIFACT is not an artifact of the change’s schema, with no_artifact_ready when ARTIFACT is omitted and nothing is ready, with template_not_found when a project schema declares a template file it does not hold, and with unknown_role, invalid_role_activation or role_not_disableable when a role setting is invalid — as does codev status.

The skills call it with --json; see codev instructions.

codev sync

Merge a change's deltas into the main specs without archiving

Usage: codev sync [OPTIONS]

Options:
      --change <CHANGE>  Change name (inferred when there is only one)
      --json
  -h, --help             Print help

Validates the change, refuses if validation reports an error, then merges its deltas into the main specs, without moving the change. Running it again reports the specs as unchanged. See Sync.

codev review

Show a change's review record and what is left to decide

Reads `_codev/changes/<name>/review.md`: per step and per role, the findings with their severity, status and location, and who must act next (author, reviewer or human). Lists the record's defects, as `codev validate` does, and whether the review lets the change be archived. Exits with 1 when the record has an error.

Usage: codev review [OPTIONS]

Options:
      --change <CHANGE>
          Change name (inferred when there is only one)

      --json


  -h, --help
          Print help (see a summary with '-h')

Reads the change’s review record and prints it per step and per role, with who must act next on each finding, the record’s defects (the review_* codes of codev validate) and whether the review lets the change be archived. Without a record, it says so and succeeds. The archive gate does not change the exit status: codev archive enforces it. JSON: review.

codev archive

Merge, then move a change to the dated archive

Usage: codev archive [OPTIONS]

Options:
      --change <CHANGE>  Change name (inferred when there is only one)
      --json
  -h, --help             Print help

Validates the change, refuses if validation reports an error, then checks its review record and refuses with review_blocked if the record is missing for a step where review roles were active or a high-severity finding is still open or disputed; then merges its deltas into the main specs and moves it, record included, to _codev/changes/archive/<YYYY-MM-DD>-<name>/. See Archive.

codev changelog

Generate release notes from the archived changes

Lists the release-note items of the changes archived after `--since` (default: the highest `v*` tag) and up to `--until` (default: the working tree), by category, breaking items first. A change archived without a release note falls back on its What Changes bullets, with a warning. `--write` keeps the `[Unreleased]` section of `CHANGELOG.md` up to date, in a managed section; with `--release`, it becomes a dated version block.

Usage: codev changelog [OPTIONS]

Options:
      --since <REF>
          Git ref the range starts after (default: the highest `v*` tag below `--until`)

      --until <REF>
          Git ref the range ends at (default: the working tree)

      --format <FORMAT>
          Output format

          Possible values:
          - keep-a-changelog: `## [Unreleased]` (or the release) and `### <Category>` sections
          - markdown:         The same without the version heading, for a release body
          - json:             The JSON contract v1

          [default: keep-a-changelog]

      --release <VERSION>
          Title the block `## [<VERSION>] - <DATE>` instead of `## [Unreleased]`

      --date <DATE>
          Release date, `YYYY-MM-DD` (default: today)

      --write
          Update `CHANGELOG.md` (created if missing); text outside codev's managed section is kept

  -h, --help
          Print help (see a summary with '-h')

Lists the release-note items of the changes archived in a git range. A change is in range when its folder is in _codev/changes/archive/ at --until and was not at --since: git decides, not dates. The default --since is the highest v* tag by version order — below --until when --until is a version tag — and, without any tag, every archived change is listed. Outside a git repository, every archived change is listed with a warning.

Items are grouped by category in Keep a Changelog order, breaking items first, then in archive order. A change whose note is None adds nothing. A change archived without a release note contributes its What Changes bullets under Changed, with a release_note_missing warning; a change whose deltas remove requirements without a Removed or breaking item gets a release_note_inconsistent warning. Warnings go to stderr and never change the exit status. Changes listed under changelog.exclude are left out.

codev changelog --since v1.3.0 --format markdown
### Added

- `--format json` on `codev export`.

### Fixed

- `codev export` no longer drops the last line.

--write updates CHANGELOG.md instead of printing the text: the [Unreleased] block lives in a managed section right after the file header, and the rest of the file is never rewritten. With --release X.Y.Z, the block becomes ## [X.Y.Z] - <date> below a new empty [Unreleased]. --write is refused with --format markdown. See Release notes and CHANGELOG.

codev validate

Check changes and specs for structural errors and consistency

Usage: codev validate [OPTIONS] [ITEM]

Arguments:
  [ITEM]  Name of a specific change or spec capability

Options:
      --all      Validate all active changes and all main specs
      --changes  Validate all active changes
      --specs    Validate all main specs
      --strict   Treat any finding (warnings included) as a reason for a non-zero exit code. Useful for CI and automation
      --json
  -h, --help     Print help

Without ITEM or a flag, validates everything: every active change, every main spec, and the decision seals. ITEM is the name of an active change or the path of a capability (ui/theme).

Exit status:

ResultWithout --strictWith --strict
No finding00
Warnings only01
At least one error11
change add-dark-mode — _codev/changes/add-dark-mode
  error   _codev/changes/add-dark-mode/change.yaml:1: zero_delta_without_marker — no delta file under `specs/` and `skip_specs: true` is not declared; add a delta or set `skip_specs: true` in change.yaml

decisions decisions — _codev/decisions
  ✓ no issues

2 item(s) validated, 1 finding(s) including 1 error(s).

Each finding has a stable code. See Validation codes.

codev roles

List the roles active at a workflow step, with their criteria

With `--at`, the roles active at that step and their "done when" criteria, each with its origin (`built-in`, `schema:<name>`, `project`). Without it, every role with its activation. The roles come from codev's built-in catalog and the schema in use, with the project's `roles:` applied, and, with `--change`, the change's `change.yaml` and the domains its proposal ticks, which activate the experts. With `--change`, also the change's diff since the default branch and the domains its experts' triggers suggest. The `By stack` part of the knowledge keeps the languages detected in the project.

Usage: codev roles [OPTIONS]

Options:
      --at <STEP>
          The workflow step: plan.understand, plan.investigate, plan.write, plan.trace, plan.challenge, code.implement or code.review

      --change <CHANGE>
          Apply this change's schema, `change.yaml` and domains

      --knowledge
          Also print each role's knowledge (always in the JSON, for active roles)

      --all-stacks
          Serve the knowledge's `By stack` part for every language, not only the languages detected in the project

      --json


  -h, --help
          Print help (see a summary with '-h')

Lists the roles a skill applies at a workflow step: with --at, the roles active at that step, each with its question and its “done when” criteria prefixed by their origin; without --at, one line per role with its steps or artifact and its activation — never (project) when your configuration disables it, on_domain: <domain> for an expert, cannot be disabled for the artifact roles, the analyst and the developer. --knowledge also prints each role’s knowledge after its criteria, after a line naming the languages its By stack part is filtered for. A step whose roles are all inactive prints No role is active at <step>: skip this step. It writes no file.

With --change, it first prints the change’s diff — the default branch it starts from, the files changed and read, the files skipped per category — or why there is none, then one line per suggested domain: its state (ticked, justified, unticked), its first trigger with its source, and the file that matched. Reading the diff runs local git commands only; outside git it says so and goes on.

The knowledge’s By stack part keeps the languages detected from the project’s dependency manifests; --all-stacks serves every language. With no manifest found, everything is served.

Without --change, it applies the project’s configured schema and roles:; unlike the other commands, it does not infer a change. With --change, it applies the change’s schema, its change.yaml and the domains its proposal ticks, which activate the experts; without it, the experts stay inactive. It fails with unknown_step when --at is not one of the steps, and with unknown_role, invalid_role_activation or role_not_disableable when a role setting is invalid — see Configuring roles. With --at, a last line names the roles of the step that the configuration turned off, each with the file whose setting did it (project or change). The skills call it with --json; see codev roles.

codev schemas

List the available workflow schemas

Usage: codev schemas [OPTIONS]

Options:
      --json
  -h, --help  Print help

Lists the project’s schemas from _codev/schemas/ and the built-in spec-driven, with the order of their artifacts. A project schema named spec-driven replaces the built-in one. A project schema that cannot be used is left out of the list with a warning schema_unusable giving the reason; the others are still listed. A project schema is named after its folder: one whose name: says otherwise is listed under its folder name, with a warning schema_name_mismatch. See Custom schemas.

Decisions

codev decision

Create, accept, inspect and supersede architecture decisions

Usage: codev decision <COMMAND>

Commands:
  list       List local and inherited decisions
  show       Show a specific decision
  new        Create a new local decision
  accept     Accept a proposed decision: set its status to `accepted` and seal it
  supersede  Create a proposed decision that will supersede an accepted one
  seal       Add or rewrite the seal of a local decision
  deviate    Record a local deviation from an inherited decision
  promote    Promote a `### Decision: <title>` block of a `design.md` to an ADR
  help       Print this message or the help of the given subcommand(s)

Options:
  -h, --help  Print help

Decisions are identified by their short id (0007) or their qualified id (project/0007, path:~/shared/0100, git:git@github.com:acme/shared.git/0100). See Decision.

codev decision list

List local and inherited decisions

Usage: codev decision list [OPTIONS]

Options:
      --json
  -h, --help  Print help

Lists local and inherited decisions with their status. Decisions in effect are marked •, the others –; a superseded decision names the one that replaced it.

codev decision show

Show a specific decision

Usage: codev decision show [OPTIONS] <ID>

Arguments:
  <ID>  Short (`0007`) or qualified (`path:~/shared/0100`) identifier

Options:
      --json
  -h, --help  Print help

Prints a header — the short and qualified id, title, status, date, then tags, Supersedes and Superseded by when set, and the file’s path, relative to the project or absolute for an inherited source outside it — followed by the file’s content. Fails with unknown_decision_id when no decision matches, and with ambiguous_decision_id, listing the candidates, when a short id matches several: use the qualified id then.

codev decision new

Create a new local decision

The decision is created `proposed` and unsealed, so its body can be written freely; `codev decision accept` then accepts and seals it.

Usage: codev decision new [OPTIONS] <TITLE>

Arguments:
  <TITLE>
          Free-form title — slugified for the file name

Options:
      --status <STATUS>
          Initial status; `accepted` seals the body right away, `proposed` leaves it editable until `codev decision accept`

          [default: proposed]

      --json


  -h, --help
          Print help (see a summary with '-h')

Creates _codev/decisions/NNNN-<slug>.md from the ADR template, with the next free number. With the default proposed status, the decision is not sealed: write its body, then run codev decision accept to accept and seal it. --status accepted seals it immediately, for a decision whose text is already final.

codev decision accept

Accept a proposed decision: set its status to `accepted` and seal it

Rewrites the frontmatter status of a local `proposed` decision and records the hash of its body in `seal.yaml`, in the same plan — all writes happen or none does. The body is left untouched. The decisions listed in its `supersedes` are marked `superseded` in the same plan; each must still be `accepted`. This is how a decision created by `new`, `supersede`, `deviate` or `promote` takes effect. Inherited decisions and decisions that are not `proposed` are refused.

Usage: codev decision accept [OPTIONS] <ID>

Arguments:
  <ID>
          Short identifier (`0007`) — inherited ones (`path:` / `git:`) are refused

Options:
      --json


  -h, --help
          Print help (see a summary with '-h')

Sets the status of a local proposed decision to accepted and records the SHA-256 of its body in _codev/decisions/seal.yaml, in the same plan: both are written or neither is. Only the frontmatter changes. An inherited decision is refused with cannot_accept_inherited, a decision that is not proposed with decision_not_proposed; to replace an accepted decision, use codev decision supersede.

This is the only command that makes a decision take effect, whichever command created it. When the decision lists predecessors in supersedes — as one created by codev decision supersede does — the same plan sets each of them to superseded; their body, and therefore their seal, is not touched. A predecessor that is no longer accepted, for example because another decision superseded it in the meantime, is refused with predecessor_not_accepted, and nothing is written.

codev decision accept 0002
✓ Accepted 0002 — sealed (sha256:c8873b83c178dbf8434045f43a722911b9d9913ee9f13915ccda893539b788c1)
  File: /home/you/acme-app/_codev/decisions/0002-use-sqlite.md
  Superseded: project/0001 (status: superseded)

codev decision supersede

Create a proposed decision that will supersede an accepted one

The new decision is created `proposed` and unsealed, with the old one in its `supersedes`. The old decision is not modified and stays in effect until `codev decision accept` accepts the new one, which marks the old one `superseded` in the same step.

Usage: codev decision supersede [OPTIONS] <OLD_ID> <NEW_TITLE>

Arguments:
  <OLD_ID>
          Identifier of the decision to supersede (short or qualified)

  <NEW_TITLE>
          Title of the new decision

Options:
      --json


  -h, --help
          Print help (see a summary with '-h')

Creates a new proposed decision, unsealed, with supersedes pointing at OLD_ID. The old decision is not modified: it stays accepted, and in effect, until you accept the new one with codev decision accept, which sets it to superseded in the same step. OLD_ID must be an accepted local decision; otherwise the command refuses with predecessor_not_accepted. To depart from an inherited decision, use codev decision deviate.

codev decision supersede 0001 "Use SQLite"
✓ Decision `0002 Use SQLite` created (proposed), to supersede `project/0001`
  New ADR:     /home/you/acme-app/_codev/decisions/0002-use-sqlite.md
  Old ADR:     /home/you/acme-app/_codev/decisions/0001-use-postgresql.md (unchanged, still in effect)

Open the new file to write the Context, Decision and Consequences sections,
then run `codev decision accept 0002` to accept and seal it.
Accepting it marks `project/0001` superseded; until then it stays in effect.

codev decision seal

Add or rewrite the seal of a local decision

Without `--force`: refuses if a seal exists and the body has changed. With `--force`: rewrites the seal (use after a deliberate edit of the body).

Usage: codev decision seal [OPTIONS] <ID>

Arguments:
  <ID>
          Short identifier (`0007`) — inherited ones (`path:` / `git:`) are refused

Options:
      --force
          Rewrite an existing seal even if the body has changed

      --json


  -h, --help
          Print help (see a summary with '-h')

Records the SHA-256 of the decision’s body in _codev/decisions/seal.yaml. Sealing an already sealed, unchanged decision does nothing.

codev decision deviate

Record a local deviation from an inherited decision

Creates a local `proposed` ADR, unsealed, that explicitly references the inherited decision being departed from. The deviation takes effect once `codev decision accept` accepts it: the inherited decision then stays visible in `codev decision list`, but disappears from the instructions injected into the `design` artifact. To deviate from a local decision, use `codev decision supersede`.

Usage: codev decision deviate [OPTIONS] <TARGET> <NEW_TITLE>

Arguments:
  <TARGET>
          Qualified identifier of the inherited decision to set aside

          Example: `path:~/shared/0100` or `git:git@github.com:acme/shared.git/0100`.

  <NEW_TITLE>
          Free-form title of the local deviation — slugified

Options:
      --json


  -h, --help
          Print help (see a summary with '-h')

The deviation is created proposed: the inherited decision stays in effect until you accept the deviation with codev decision accept. See Inherited decisions.

codev decision promote

Promote a `### Decision: <title>` block of a `design.md` to an ADR

Extracts the block's content into a `proposed` local ADR, unsealed, and replaces the block's body with a textual reference to the new ADR. Review and rework the ADR, then accept and seal it with `codev decision accept`. Refuses an archived change.

Usage: codev decision promote [OPTIONS] <CHANGE> <TITLE>

Arguments:
  <CHANGE>
          Name of the active change whose `design.md` holds the block

  <TITLE>
          Exact title of the block to promote (what follows `Decision: `)

Options:
      --json


  -h, --help
          Print help (see a summary with '-h')

The ADR is created proposed, with the block’s text verbatim under ## Decision and placeholders for the other sections. Rework it, then accept and seal it with codev decision accept:

codev decision promote add-audit-log "Append-only audit table"
✓ Decision `Append-only audit table` promoted to proposed ADR 0004
  File:    /home/you/acme-app/_codev/decisions/0004-append-only-audit-table.md
  Source:  /home/you/acme-app/_codev/changes/add-audit-log/design.md

Review the ADR promoted from change `add-audit-log`: split its body into Context,
Decision, Consequences and Alternatives considered,
then run `codev decision accept 0004` to accept and seal it.

Inherited sources

codev sources

Manage inherited sources (local paths and remote git repositories)

Usage: codev sources <COMMAND>

Commands:
  list    List all declared sources with their state
  update  Resolve refs, download, and update `_codev/codev.lock`
  show    Show the details of a specific source
  help    Print this message or the help of the given subcommand(s)

Options:
  -h, --help  Print help

See Inherited sources.

codev sources list

List all declared sources with their state

Usage: codev sources list [OPTIONS]

Options:
      --json
  -h, --help  Print help

codev sources show

Show the details of a specific source

Usage: codev sources show [OPTIONS] <TARGET>

Arguments:
  <TARGET>  URL (`git:` source) or path (`path:` source)

Options:
      --json
  -h, --help  Print help

codev sources update

Resolve refs, download, and update `_codev/codev.lock`

Usage: codev sources update [OPTIONS]

Options:
      --json
  -h, --help  Print help

The only command that uses the network. Requires git.

Configuration

A codev project is configured by _codev/config.yaml. Every key is optional: a project can even run without the file. A key codev does not know is reported — as a warning at the top level, in mcp and in review, as an error elsewhere — so a typo never goes unnoticed; see Unknown keys.

codev init generates the file with the values it detected, each preceded by a comment giving its source. You can edit it by hand at any time. After changing workflows, mcp or review, run codev update so the skills reflect the change.

Complete example

schema: spec-driven

language: en

workflows:
  - propose
  - explore
  - onboard
  - apply
  - sync
  - archive
  - update
  - configure

context: |
  TypeScript monorepo: a Next.js web app and a Node.js API.
  Errors are typed; never throw raw strings.

rules:
  specs:
    - Describe observable behavior, never implementation.
  design:
    - Cite the decisions in _codev/decisions/ that constrain the approach.
  tasks:
    - "Each task states how to verify it: a named test, a command, or an observable behavior."

inherits:
  - path: ~/src/acme-standards
  - git: git@github.com:acme/codev-standards.git
    ref: main
    subpath: standards

mcp:
  jira_tool: mcp__atlassian__getJiraIssue

changelog:
  exclude:
    - 2026-03-02-legacy-import

codev_version: ">=0.5"

roles:
  newcomer: never
  skeptic:
    done_when:
      - The rollback plan is stated

triggers:
  - domain: personal-data
    paths: ["src/billing/**"]

review:
  mode: isolated

schema

The workflow schema used by new changes. Default: spec-driven, the schema embedded in codev. The name of a schema defined under _codev/schemas/ is also accepted. A change records its schema in its own change.yaml, so changing this key does not affect changes in progress. See Custom schemas.

language

The language skills write artifact prose in, as an ISO 639 code: two or three lowercase letters, optionally followed by one subtag (en, fr, pt-BR, zh-Hant). Default: en. The skills write the structural keywords in English; codev reads them in English or French whatever this setting. See Artifact language.

workflows

The workflows to install as Claude Code skills, by id: propose, explore, onboard, configure, apply, sync, archive, update. When the key is absent, all eight are installed. An unknown id produces an unknown_workflow warning and is ignored. See Claude Code skills.

context

Free text given to the agent with the instructions of every artifact: your stack, conventions, constraints — what cannot be inferred from the code. It is a constraint on the agent, never content to copy into the files. /codev-configure can draft it for you.

rules

Rules for one artifact, as a map from artifact id to a list of strings. With the spec-driven schema, the ids are proposal, specs, design and tasks. Each rule is handed to the agent only when it writes that artifact.

YAML reads key: value inside a plain scalar as a map, so quote a rule that contains a colon followed by a space, as in the tasks rule above.

/codev-propose applies the rules a second time when it challenges the finished plan, so rules is also the way to add a review lens specific to your project:

rules:
  design:
    - "Assess the accessibility (RGAA) impact of any user-interface change."

Testing rules go under tasks: /codev-propose writes the plan with them, and /codev-apply follows them when it writes the tests. Describe what your existing tests do — /codev-configure drafts the rule from them:

rules:
  tasks:
    # One rule for your stack, for example:
    # Rust
    - "Unit tests in #[cfg(test)] mod tests next to the code, integration tests in tests/; cargo test, cargo clippy -- -D warnings, cargo fmt --check."
    # TypeScript
    - "Vitest, *.test.ts next to the code, Testing Library for components; tsc --noEmit and the linter in CI."
    # Python
    - "pytest, tests/ mirroring the package, fixtures and parametrize; ruff check."
    # Go
    - "Table-driven tests in _test.go files of the same package; go test ./..., go vet."
    # Java
    - "JUnit 5 under src/test/java mirroring the main package, Mockito only at boundaries; mvn verify."

While rules is empty, codev init and codev status suggest running /codev-configure.

inherits

Read-only sources to inherit context, rules and decisions from, in order from the most general to the most specific. Each entry is either a local folder or a git repository:

KeyApplies toMeaning
pathlocalFolder containing a codev project; absolute or starting with ~
gitgitRepository URL, as git understands it
refgitBranch or tag to follow — required
subpathgitFolder of the repository that contains the codev project

An entry declares exactly one of path and git; ref and subpath are rejected on a path entry. Git sources are pinned in _codev/codev.lock by codev sources update. See Inherited sources.

codev init --inherit <SOURCE> writes this key for you when it creates the configuration, one entry per flag, under a # set with codev init --inherit comment, and pins the git sources at once:

codev init --yes --inherit git@github.com:acme/codev-standards.git@v2 --inherit ~/src/acme-standards
# set with codev init --inherit
inherits:
  - git: git@github.com:acme/codev-standards.git
    ref: v2
  - path: ~/src/acme-standards

mcp

Names of the MCP tools the skills may call. These are specific to each Claude Code setup, so they are never inherited.

KeyMeaning
jira_toolTool that fetches a Jira issue, used by /codev-propose when a ticket id is mentioned

See Jira and other MCP servers.

changelog

Settings of codev changelog. Project only, never inherited.

KeyMeaning
excludeArchive folder names (<date>-<name>) of changes already described by hand in CHANGELOG.md. codev changelog leaves them out, without a warning

Use it when adopting codev changelog in a project whose CHANGELOG.md already describes changes archived without a release note, so they are not listed twice. See Release notes and CHANGELOG.

codev_version

The codev versions the team accepts, as a semantic version requirement in Cargo’s syntax: ">=0.5", "^0.6", ">=0.5, <0.8". Quote it, since YAML reads > specially. Project only, never inherited.

When the running codev does not satisfy it, codev doctor reports the codev_version check as missing and the skills offer to update before acting. The fix is codev self-update when the running codev is too old. When it is too new — above an upper bound such as <0.7 — a plain codev self-update would refuse to downgrade, so the fix names a version: codev self-update --version 0.6.4, taken from the latest release the update cache knows when it satisfies the requirement, otherwise from the requirement itself (<=0.6.2 gives 0.6.2, ^0.5 gives 0.5.0). A value that is not a requirement makes every command fail with invalid_codev_version.

codev 0.5 and earlier do not know this key and reject the file: add it once everyone runs a version that does.

roles

Which roles run, and the criteria your project adds to them. Project only, never inherited. Each key is a role id; its value is either an activation, or a mapping:

KeyMeaning
whenalways, never or on_domain; the default is on_domain for the experts, always for every other role. on_domain activates a role only for a change whose proposal ticks one of its domains. A step whose roles are all inactive is skipped, and the skill says so
done_whenCriteria added after the role’s own, with the origin project; blank entries are ignored
roles:
  newcomer: never            # short form
  security: always           # the security expert reviews every change
  skeptic:
    when: always
    done_when:
      - The rollback plan is stated

The ids are the built-in step roles (analyst, investigator, tracer, skeptic, developer, newcomer), the experts (security, privacy, accessibility, performance, ops, migration — see Experts and domains) and the artifact roles of the schema in use (product, qa, architect, lead with spec-driven). The artifact roles, the analyst and the developer cannot be disabled; their criteria can be extended. A change’s change.yaml can override the activation for that change only — see change.yaml.

codev validate reports an unknown id as unknown_role, an activation other than always, never or on_domain — or on_domain on a role bound to no domain — as invalid_role_activation, and never on a role that cannot be disabled as role_not_disableable — errors of the config item, at the line of the role. codev status, codev instructions and codev roles fail with the same code. Any other key inside a role’s mapping, such as a misspelled done-when, fails every command with invalid: ignoring it would drop criteria silently.

triggers

Your project’s own triggers: the paths and patterns only your team knows to be sensitive. Project only, never inherited. A list of groups, each naming the domain it suggests and holding at least one of paths, manifests or patterns:

KeyMeaning
domainsecurity, personal-data, user-interface, performance, operations or migration
pathsGlobs over the changed files, relative to the project root, ignoring case; * stays within a folder, ** crosses folders
manifestsFile names of dependency manifests, matched at any depth
patternsRegular expressions over the lines the diff adds
triggers:
  - domain: personal-data
    paths: ["src/billing/**", "src/crm/**"]
    patterns: ['\bcustomer_id\b']
  - domain: migration
    paths: [api/public.yaml]

Quote a glob that starts with *: in YAML, * starts an alias. Their matches have the source project, and they are evaluated whatever your roles: settings. Expressions run in linear time, whatever their shape, and their compiled size is capped.

codev validate reports, at the line of triggers:, an invalid_trigger error for a group without a known domain, without any trigger, or with a glob or an expression that does not compile — the group is then ignored by every command, which says so in its status — and an invalid_trigger warning for a key it does not know, which is ignored while the rest of the group is used.

codev 0.6 and earlier do not know this key: they warn unknown_config_key, which fails their codev validate --strict. When you add it, raise codev_version to the release that introduced it.

review

How the reviewing roles run. Project only, never inherited.

KeyMeaning
modeinline (default): the skill reviews in its own conversation, one role after the other. isolated: each reviewing role runs alone as a Claude Code sub-agent that never sees the conversation, then the skill merges their findings
review:
  mode: isolated

A change can override it in its change.yaml, with the same key: review: { mode: inline } for a typo fix in an isolated project, or isolated for one sensitive change in an inline project. codev roles --json gives the mode in effect and where it comes from (review.mode, review.origin). Any other value fails every command with invalid_review_mode, naming inline and isolated; an unknown key under review is an unknown_config_key warning (review.<key>).

Switching. Set the key, then run codev update: in isolated mode the /codev-propose and /codev-apply skills request Claude Code’s Agent tool, in inline mode they do not, and codev doctor reports skills_review_mode until they are regenerated. A skill you edited by hand is kept; codev update --force rewrites it.

Why inline is the default. Isolated review multiplies the reading of the material by the number of roles, and its benefit has not been measured yet: codev’s role evaluations run one role at a time, with no authoring conversation, so they cannot compare the two modes. See Inline or isolated review.

codev 0.6 and earlier do not know this key: they warn unknown_config_key — which fails their codev validate --strict — and refuse a change.yaml that sets it. When you set it, raise codev_version to the release that introduced it, so every codev that reads the repository, CI included, understands it.

Unknown keys

A newer codev may add keys an older one does not know. So that an older codev keeps working on a newer configuration and tells you what it needs, unknown keys are treated according to what ignoring them would do:

WhereUnknown keyWhy
top levelwarning unknown_config_key, key ignoredeach key is an independent feature: the rest of the configuration still applies
mcpwarning unknown_config_key (mcp.<key>), key ignoredan unknown tool only leaves that integration unconfigured
reviewwarning unknown_config_key (review.<key>), key ignoredan unknown review setting leaves the review as it was
an inherits entryerror invalidignoring it would read another source than the one you described
changelogerror invalidignoring it would make codev changelog --write write another file
a roles entryerror invalidignoring it would drop criteria or an activation
a triggers groupwarning invalid_trigger from codev validate, key ignoredthe rest of the group still suggests its domain

The warning names the key, says the project may need a newer codev, quotes codev_version when the file sets it, and points to codev self-update; the error does the same when codev_version is set. The warning appears:

  • in the output of codev status, codev new change, codev init and codev update, and in the status array of their --json output;
  • in codev validate, as a warning finding of a config item at the line of the key, so codev validate --strict — the CI case — fails on it while plain codev validate passes;
  • in codev doctor, as the config.keys check.

The keys of an inherited source’s configuration are not reported: only its context and rules are read.

This tolerance starts with the codev release that introduced it: codev 0.5 and earlier reject any unknown key, at any level. When you add a key that only recent versions know, raise codev_version too, so that teammates on an older codev learn from codev doctor and the skills which version to install.

Environment variables

VariableUsed byEffect
LC_ALL, LC_MESSAGES, LANGcodev initDefault for language: when --language is not given
XDG_CACHE_HOMEgit sources, update checkCache location: $XDG_CACHE_HOME/codev/, else ~/.cache/codev/
CIcodev statusAny value disables the update check
CODEV_NO_UPDATE_CHECKcodev status1 disables the update check
VISUAL, EDITORcodev initEditor opened when the context question is left empty
CODEV_VERSIONinstall.sh, install.ps1Version to install instead of the latest

File formats

codev’s files are Markdown and YAML meant to be written by people and agents, and parsed by codev. This chapter gives the exact rules, with the English keywords. codev also reads their French equivalents (### Exigence :, ## Exigences AJOUTÉES, DOIT…), listed in Artifact language.

Everything inside fenced code blocks and HTML comments is ignored by the parsers, so templates can carry guidance in <!-- … --> comments.

Main spec

Path: _codev/specs/<capability>/spec.md, where <capability> is one or more kebab-case segments (ui/theme). Only a file named exactly spec.md is a main spec: other files under _codev/specs/, such as a README.md, are ignored by codev list --specs and codev validate.

# Theme Specification

## Purpose

Let users choose the color theme of the interface.

## Requirements

### Requirement: Theme follows the system preference by default

The application SHALL render with the operating system's color scheme until the user picks a theme.

#### Scenario: No theme chosen yet

- **GIVEN** a user who has never changed the theme setting
- **WHEN** their operating system is set to dark mode
- **THEN** the application renders with the dark theme
  • ## Purpose is required.
  • Requirements are ### Requirement: <name> headings inside ## Requirements. The name identifies the requirement in deltas, so keep it unique within the spec.
  • A requirement’s description contains a normative keyword in upper case: SHALL or MUST, or DOIT or DOIVENT.
  • Every requirement has at least one #### Scenario: <name>, with exactly four # characters. Scenario steps are bullet lines using **GIVEN**, **WHEN**, **THEN** and **AND**.
  • Other ## sections are allowed and preserved by merges.
  • Delta headings (## ADDED Requirements…) are not allowed in a main spec.

When archiving creates a main spec for a new capability, it titles it from the last segment of the capability path (# Theme Specification) and copies the delta’s ## Purpose.

Spec delta

Path: _codev/changes/<name>/specs/<capability>/spec.md, with the same capability path as the main spec it modifies.

## ADDED Requirements

### Requirement: The chosen theme is remembered

The application SHALL restore the theme the user last picked, on every device they sign in from.

#### Scenario: Returning user

- **GIVEN** a user who picked the dark theme on their laptop
- **WHEN** they sign in on their phone
- **THEN** the application renders with the dark theme

## MODIFIED Requirements

### Requirement: Theme follows the system preference by default

<the complete requirement, scenarios included, as it must read after the change>

## REMOVED Requirements

### Requirement: Legacy color picker

**Reason**: Replaced by the theme setting.
**Migration**: Users' custom colors are dropped; the default theme applies.

## RENAMED Requirements

- FROM: Theme follows the system preference by default
- TO: Theme follows the system preference until the user chooses
SectionContentMerge
## ADDED RequirementsComplete new requirementsAppended at the end of ## Requirements
## MODIFIED RequirementsComplete requirements, with an existing nameEach replaces the requirement of the same name
## REMOVED RequirementsA ### Requirement: heading with **Reason**: and **Migration**: linesThe requirement is deleted
## RENAMED RequirementsFROM: / TO: line pairs, with or without a leading - The heading is retitled; body and scenarios are untouched

In RENAMED, write after FROM: and TO: either the bare requirement name, as above, or the full heading in backticks, as the template does: - FROM: `### Requirement: <old name>`.

Rules checked by validation:

  • A requirement appears in at most one of ADDED, MODIFIED and REMOVED (cross_section_conflict), and at most once per section (duplicate_requirement).
  • Inside a delta section, every ### heading is a ### Requirement: (delta_unexpected_heading); a section with no entry is reported as a warning (delta_section_empty).
  • A RENAMED source must exist in the main spec (rename_source_missing, unless the rename was already applied by an earlier sync); a RENAMED target cannot also be ADDED (rename_target_collision); and MODIFIED uses the new name of a renamed requirement, not the old one (modified_uses_old_name).
  • MODIFIED and REMOVED names must exist in the main spec; this is checked when the delta is merged (modified_target_missing).
  • New capability: start the delta with ## Purpose. For an existing capability, omit it — the main spec’s Purpose is kept.
  • A REMOVED delta that would leave a spec with no requirement is refused (would_leave_spec_without_requirement) unless the change declares retire_capabilities: true; the main spec is then deleted.

proposal.md

The spec-driven template:

# Proposal: <change title>

## Why

## What Changes

## Capabilities

### New Capabilities

### Modified Capabilities

### Removed Capabilities

## Impact

## Domains

## Release note

Each capability listed under New or Modified Capabilities gets its own delta file at specs/<capability>/spec.md. Breaking changes are marked BREAKING in What Changes. A capability listed under Removed Capabilities requires retire_capabilities: true.

Release note

What end users read in the changelog, built by codev changelog. Either one or more items:

## Release note

- Added: `--format json` on `codev export`.
- Changed: **BREAKING** `codev export` writes to stdout by default; pass
  `--output <PATH>` to write a file.

or, for a change users will not notice, the single line:

## Release note

None

Each item is - <Category>: <text>, the category being one of Added, Changed, Deprecated, Removed, Fixed and Security — the categories of Keep a Changelog. An item may wrap over several lines. A breaking item starts its text with **BREAKING**. The text follows the project’s artifact language. codev validate reports a missing section as a warning and an unknown category, an item without text or an empty section as errors, on active changes only.

Domains

The domains the change touches, which activate their experts. The template lists the six domains unticked; tick the ones the change touches:

## Domains

- [x] security
- [ ] personal-data
- [ ] user-interface
- [ ] performance
- [x] operations — a new background worker
- [ ] migration

or, when it touches none of them, write the single line None.

- [x] <domain> or - <domain> ticks a domain, - [ ] <domain> leaves it unticked, and the text after the domain name is a free comment. The domains are security, personal-data, user-interface, performance, operations and migration. codev validate reports, on active changes only, an unknown domain (unknown_domain) and a line that is neither an item nor None, or None next to a ticked domain (domains_invalid), as errors, and a missing section (domains_missing) as a warning.

That comment is also how you answer a suggested domain the change does not touch: an unticked domain with a reason after its name is justified — - [ ] security — only renames a variable. Leading dashes, colons and spaces are not part of the reason; None justifies nothing. codev validate reports each suggested domain neither ticked nor justified as domain_suggested, a warning at the domain’s line.

design.md

# Design: <change title>

## Context

## Goals / Non-Goals

## Decisions

### Decision: <the choice>

**Alternatives considered**:

## Risks / Trade-offs

## Migration Plan

## Open Questions

Each ### Decision: <title> block can be promoted to an ADR with codev decision promote <change> "<title>". Risks / Trade-offs uses the [Risk] → Mitigation form. Migration Plan and Open Questions are removed when they do not apply.

tasks.md

# Tasks

## 1. Theme tokens

- [ ] 1.1 Move every color to a CSS custom property, verified by a visual diff of the settings page
- [ ] 1.2 Add the dark token set, verified by `npm test -- theme`

Tasks are grouped under numbered ## headings and written as - [ ] X.Y <task>; /codev-apply checks them off as - [x]. Each task states how to verify it.

change.yaml

Path: _codev/changes/<name>/change.yaml. Written by codev new change. <name> is never archive, the folder of archived changes.

schema: spec-driven
created: 2026-09-30
goal: Let users switch the UI to a dark theme
KeyTypeMeaning
schemastring, requiredSchema of the change: spec-driven, or the folder name of a project schema under _codev/schemas/
createddateCreation date, YYYY-MM-DD
goalstringThe goal given with --goal
skip_specsbooleanThe change intentionally has no spec delta: the artifacts writing under specs/ are skipped, and validation accepts zero deltas
retire_capabilitiesbooleanAllows sync and archive to delete a main spec whose last requirement the change removes
rolesmappingRole activations for this change only, over the project’s roles:: newcomer: always. Activations only — criteria belong to the project
reviewmappingmode: inline or mode: isolated for this change only, over the project’s review:. Another value fails with invalid_review_mode

Unknown keys are rejected — inside review too. A codev that predates review refuses a change.yaml that sets it: raise the project’s codev_version to the release that introduced it before using it. A change folder without change.yaml uses the project’s schema. An invalid entry of roles is reported by codev validate as an error of the change (unknown_role, invalid_role_activation, role_not_disableable).

The artifacts of a schema.yaml may declare their role as data under role: — see Custom schemas.

review.md

Path: _codev/changes/<name>/review.md. The change’s review record, written by /codev-propose (plan.challenge) and /codev-apply (code.review), or by hand. It is not a planning artifact: codev status ignores it, codev sync leaves it, codev archive moves it with the change.

# Review record: add-sessions

<!-- codev-review: 1 -->

## plan.challenge

### skeptic

No finding.

### security

#### R-security-1 Session tokens are stored in clear

```yaml
severity: high
confidence: high
location: "design.md#Decision: Sessions live in the database"
evidence: |
  The session token is stored in the `sessions` table.
recommendation: Store a SHA-256 of the token and compare digests.
history:
  - status: open
    by: security
  - status: fixed
    by: architect
    ref: design.md, the decision now stores a digest
  - status: fixed
    by: security
    note: verified
```

## code.review

### newcomer

Disabled by configuration.
ElementRule
<!-- codev-review: <n> -->Optional format marker; without it, format 1. A greater format is not checked and blocks archiving
## <step>plan.challenge or code.review, once each
### <role-id>One per role under a step, once each. Holds findings, or the line No finding., or the line Disabled by configuration.
#### <id> <title>A finding: R-<role-id>-<n>, unique in the record, never reused, followed by one fenced yaml block
Mode: <mode>.Optional, under a step: inline or isolated, how the step was reviewed. Once per step
Summarized: <text>.Optional, under a step, any number: a file of the material the reviewers received as a summary
Fallback: <reason>.Optional, under a role, once: why the role reviewed inline in an isolated review
FieldTypeMeaning
severityhigh, medium or lowSee the scale
confidencehigh or lowA low finding is not presented to the human
locationstring<path>:<line> or <path>:<start>-<end> from the project root, or <file>#<heading> from the change folder. Relative, no .., no drive; \ reads as /. Quote it when it holds :
evidencestringThe cited text, verbatim: whole lines or a fragment of each
recommendationstringWhat to do
historylistThe answers, oldest first; the last one is the status
raised_bylist, optionalEvery role that raised the finding, its own role first, each once: a finding merged from several reviewers in an isolated review
history[] keyMeaning
statusopen, fixed, disputed, accepted-risk, deferred or rejected
byA role id, human, or human:<name>
refThe commit or the file change — required by fixed after open or disputed
noteThe argument (disputed), the justification (accepted-risk, by a human), or why a fix does not hold (open after fixed)
toWhere a deferred finding goes: a change or an issue. A high one is deferred by a human

A field this codev does not know is a warning, review_unknown_field, and is ignored: a later codev may add optional fields without changing the format. A new status, step or required field raises the format marker instead, which an older codev refuses to check. The transitions and the checks are in Review record.

Decision (ADR)

Path: _codev/decisions/NNNN-<slug>.md. Every .md file in this folder is parsed as a decision.

---
id: "0003"
title: "Use SQLite for persistence"
status: accepted
date: 2026-09-30
tags: [storage]
supersedes: ["0001"]
---

## Context

## Decision

## Consequences

## Alternatives considered
FieldRequiredMeaning
idyesShort id, conventionally four digits; quote it so YAML keeps it a string
titleyesTitle
statusyesaccepted, superseded, proposed, deprecated or rejected
dateyesYYYY-MM-DD
tagsnoList of tags
supersedesnoId, or list of ids, of the decisions this one replaces
deviates_fromnoList of qualified ids of inherited decisions this one departs from

The frontmatter is delimited by --- lines at the very start of the file. The body is split into ## sections; the template’s four sections are a convention, not a requirement. Only accepted decisions that are not superseded or deviated from are in effect, and supersedes and deviates_from only take effect on an accepted decision: a proposed supersession or deviation changes nothing until codev decision accept.

Files saved with Windows line endings (CRLF) are read like any other. When codev rewrites a decision’s status — codev decision accept, or a predecessor marked superseded — it keeps the file’s line endings and leaves the body byte for byte as it was, so the seal stays valid.

seal.yaml

Path: _codev/decisions/seal.yaml. Maintained by codev; do not edit it by hand.

version: 1
seals:
- id: '0001'
  bodySha256: sha256:fad1f272bf13eb44f97aba1bc22f36f294503d1a2471bf12ab4bfc6ee7b4d7f6
  sealedAt: 2026-09-30

Each entry records the SHA-256 of a decision’s body — everything after the closing --- of the frontmatter, byte for byte — and the date it was sealed. Commit this file with your decisions.

codev.lock

Path: _codev/codev.lock. Written only by codev sources update, in TOML.

version = 1

[[source]]
git = "git@github.com:acme/codev-standards.git"
ref = "main"
commit = "12958274cbed0eb66985f57d3272c6d3134b672d"
resolved_at = "2026-09-30"

One [[source]] entry per git: source, with the ref it follows, the commit it is pinned to, and, when set, its subpath. Commit this file.

SKILL.md

Path: .claude/skills/codev-<workflow>/SKILL.md. Generated by codev init and codev update:

---
name: codev-explore
description: "Explore an idea, investigate a problem or clarify a need before creating a codev change. …"
allowed-tools: "Bash(codev:*), Read, Glob, Grep"
license: MIT
metadata:
  generator: codev
  version: "0.6.1"
  checksum: "8d676b09…"
---

<workflow instructions>

metadata.checksum is the SHA-256 of the whole skill without that line. With metadata.version, it is how codev update tells codev’s renderings from your edits. codev update rewrites a skill stamped with another version; among the skills stamped with its own version, it rewrites one whose content still hashes to its checksum — codev’s rendering, from an earlier build or for the other review mode — and preserves one that no longer does, edited by hand, unless you pass --force. A skill without a checksum, rendered before checksums existed, is preserved when it carries this version’s stamp and differs from the rendering by more than the review mode: run codev update --force once to bring such skills under the checksum — it also overwrites a skill you really edited, so check git diff first and apply your edits again after; an edit made then is preserved, since it no longer matches the checksum.

Validation codes

Every finding reported by codev validate carries a stable code. Messages may be reworded between versions; codes are not.

CodeSeverityMeaning
spec_purpose_missingerrorA main spec has no ## Purpose
spec_no_requirementerrorA main spec has no requirement
requirement_outside_sectionerrorA ### Requirement: outside ## Requirements
delta_header_in_main_specerrorA delta heading in a main spec
requirement_no_shallerrorA requirement without SHALL, MUST, DOIT or DOIVENT
requirement_no_scenarioerrorA requirement without a scenario
scenario_wrong_heading_levelerrorA scenario written with three # instead of four
duplicate_requirementerrorThe same requirement twice in one delta section
delta_unexpected_headingerrorA ### heading in a delta section that is not ### Requirement:, such as a translated keyword
cross_section_conflicterrorThe same requirement in two of ADDED, MODIFIED, REMOVED
rename_source_missingerrorA RENAMED source names no requirement of the main spec
rename_target_collisionerrorA RENAMED target is also ADDED
modified_uses_old_nameerrorMODIFIED uses the old name of a renamed requirement
zero_delta_without_markererrorA change has no delta and does not declare skip_specs: true
skip_specs_conflicterrorA change declares skip_specs: true but has deltas
decision_missing_frontmattererrorA file in _codev/decisions/ has no frontmatter
decision_missing_fielderrorA decision lacks a required field, or has an unknown one
decision_unknown_statuserrorA decision has an unknown status
decision_field_type_mismatcherrorA frontmatter field has the wrong shape
decision_seal_mismatcherrorA sealed decision’s body was edited
decision_conflicting_deviationserrorTwo accepted local decisions deviate from the same inherited one
release_note_invaliderrorThe proposal’s ## Release note has an unknown category, an item without text, or is empty
release_note_missingwarningAn active change’s proposal has no ## Release note section
unknown_domainerrorThe proposal’s ## Domains names a domain outside the six
domains_invaliderrorThe proposal’s ## Domains has a line that is neither an item nor None, or None next to a ticked domain
domains_missingwarningAn active change’s proposal has no ## Domains section
domain_suggestedwarningThe change’s diff suggests a domain the proposal neither ticks nor keeps unticked with a reason
invalid_triggererrorA group of triggers: in _codev/config.yaml has no known domain, no trigger, or a glob or expression that does not compile (a warning for a key codev does not know)
review_invaliderrorThe review record’s layout, a finding’s field, id or location, a status or a transition is wrong
review_decision_incompleteerrorA history entry lacks its ref, note or to, or a risk is accepted, or a high finding deferred, by someone other than a human
review_location_missingerrorA finding cites a file, a line or a heading that does not exist
review_evidence_not_founderrorA finding’s evidence is nowhere in the cited file or section
review_role_missingerrorA role active at a recorded step has no section, or one that says it is disabled
review_evidence_movedwarningA finding’s evidence is in the file, more than 5 lines away from the cited lines
review_evidence_uncheckedwarningThe cited file is not UTF-8 text, holds NUL bytes, or is larger than 4 MiB: the evidence is not compared
review_unknown_sectionwarningA step or a role the record should not hold; it is ignored
review_unknown_fieldwarningA finding field this codev does not know; it is ignored
review_format_unsupportedwarningThe record comes from a newer codev; nothing in it is checked
delta_section_emptywarningA delta section has no entry, so nothing of it is merged
decision_unsealedwarningAn accepted or superseded local decision has no seal
unknown_config_keywarning_codev/config.yaml holds a top-level or mcp key this codev does not know — see Unknown keys
decision_orphan_sealwarningA seal has no matching decision
decision_supersedes_unknownwarningsupersedes names an unknown decision
decision_id_collisionwarningA local and an inherited decision share an id
decision_dangling_deviationwarningdeviates_from names a decision that is not indexed
decision_supersession_cyclewarningSupersessions form a cycle; none of the decisions involved is in effect

JSON output

Every command that works on a project accepts --json. The output is a public, versioned contract — version 1 — that the skills rely on, and that you can use in scripts and CI.

Guarantees

  • One document. stdout carries exactly one JSON document, pretty-printed, including when the command fails. Nothing else is printed to stdout.
  • A status array. Every document has a status array, empty when all went well, listing warnings and errors otherwise.
  • The same shape on failure. A failed command returns the shape of its successful output, with empty or null fields, plus the error in status. A consumer parses both cases with the same code.
  • Stable names. Field names are camelCase. Codes are stable and meant to be tested; messages are meant to be read and may be reworded.
  • Portable paths. Every path, absolute or relative, uses / separators on every OS — on Windows, C:/work/acme-app. Paths inside findings are relative to the project root.
  • Additive evolution. Within version 1, fields may be added, never renamed or removed. Some optional fields are omitted when empty, as noted below.

The exit status follows the same rules as in human mode: 0 on success, 1 on failure, and for codev validate, 1 when there are errors (or any finding with --strict).

The status array

{
  "status": [
    {
      "level": "error",
      "code": "ambiguous_change",
      "message": "several active changes: add-audit-log, rework — specify which one"
    }
  ]
}
FieldValues
levelerror or warning
codeA stable identifier, such as no_codev_root
messageHuman-readable text

Common error codes:

CodeMeaning
no_codev_rootNo _codev/ in the current directory or its parents
no_active_changeThe project has no active change
ambiguous_changeSeveral active changes and no --change
unknown_changeThe named change does not exist
invalid_change_idA change name that is not kebab-case, or the reserved archive; the message names the rule it breaks
change_existsnew change with a name already taken
schema_not_foundUnknown schema name
schema_invalid, schema_unreadableA schema file that codev refuses: a structural defect, or invalid YAML or an unknown key
unknown_artifactinstructions with an artifact that the change’s schema does not have
no_artifact_readyinstructions without an artifact, and none is ready
template_not_foundA schema references a missing template
validation_failedsync or archive refused a change whose validation reports errors
review_blockedarchive refused a change whose review record is missing for a reviewed step, holds a high-severity finding still open or disputed, or comes from a newer codev; the message names each reason
invalid_review_modereview.mode in _codev/config.yaml or a change’s change.yaml is neither inline nor isolated; the message names the file and the allowed values
invalidAn invalid file, or a delta that cannot be merged into its main spec
unreadableA file could not be read
write_failedA file could not be written

Warnings reuse the codes of the condition they report, for example inherit_unresolved, git_source_unlocked, unknown_workflow or artifact_skipped.

Documents by command

init and update

codev init --json and codev update --json:

{
  "root": "/home/you/acme-app",
  "created": ["…"],
  "updated": ["…"],
  "untouched": ["…"],
  "preserved": ["/home/you/acme-app/.claude/skills/codev-apply/SKILL.md"],
  "skills": ["codev-propose", "codev-explore", "…"],
  "integration": [
    {
      "step": "claude_md",
      "action": "appended",
      "path": "CLAUDE.md",
      "reason": null
    },
    {
      "step": "ci",
      "action": "skipped",
      "path": ".github/workflows/codev.yml",
      "reason": ".github/workflows/ci.yml already runs codev validate"
    },
    {
      "step": "pr_template",
      "action": "created",
      "path": ".github/PULL_REQUEST_TEMPLATE.md",
      "reason": null
    }
  ],
  "status": []
}

preserved lists the skills left in place because they were edited by hand. integration has one entry per repository integration step: step is claude_md, ci or pr_template; action is created, appended, refreshed, unchanged or skipped; path is relative to the project, or null; reason explains a skipped step, or is null. codev update only lists the managed files it found. The codev doctor hint and the GitLab snippet are human output only.

Warnings specific to init: inherit_not_written (--inherit with an existing config.yaml), inherit_pin_failed (a git source could not be pinned) and managed_section_malformed (unbalanced codev markers; the file is left untouched). An invalid --inherit value fails with invalid_inherit.

doctor

codev doctor --json:

{
  "root": "/home/you/acme-app",
  "checks": [
    {
      "id": "config.rules",
      "group": "configuration",
      "status": "missing",
      "code": "rules_missing",
      "message": "no rules: in _codev/config.yaml",
      "fix": "/codev-configure"
    },
    {
      "id": "config.language",
      "group": "configuration",
      "status": "ok",
      "code": "ok",
      "message": "language: is set",
      "fix": null
    },
    "…"
  ],
  "summary": {
    "total": 14,
    "missing": 2,
    "warnings": 1
  },
  "status": []
}

Each check has a stable id, its group, a status (ok, missing or warning), a stable code (ok when the check passes), a message, and a fix — the command or skill to run — or null when ok. Checks come in the order of the table below; pr_template is only present for GitHub repositories. summary.missing drives the exit status of --strict.

Check idgroupCodes when not ok
config.rulesconfigurationrules_missing
config.languageconfigurationlanguage_missing
config.keysconfigurationunknown_config_key (warning)
config.rolesconfigurationroles_invalid (warning); when ok, message lists the active roles, the roles active on domain with their domains, and the disabled ones
skillsconfigurationskills_missing, skills_outdated, skills_review_mode
sourcesconfigurationsource_unpinned, lock_stale (warning)
codev_versionconfigurationcodev_version_unsatisfied, update_available (warning)
specsplanningno_main_spec
decisionsplanningno_accepted_decision (warning)
validateplanningvalidate_errors, validate_warnings (warning)
claude_mdrepositoryclaude_md_section_missing
cirepositoryci_validate_missing
pr_templaterepositorypr_template_section_missing
changelogrepositorychangelog_missing (warning), changelog_outdated (warning)

changelog

codev changelog --format json (the --json of this command):

{
  "root": "/home/you/acme-app",
  "since": "v1.3.0",
  "until": null,
  "release": null,
  "entries": [
    {
      "category": "Added",
      "text": "`--format json` on `codev export`.",
      "breaking": false,
      "change": "2026-10-02-export-json",
      "archivePath": "_codev/changes/archive/2026-10-02-export-json",
      "source": "release_note"
    }
  ],
  "markdown": "## [Unreleased]\n\n### Added\n\n- `--format json` on `codev export`.\n",
  "written": null,
  "status": []
}
  • since — the ref the range starts after, explicit or the default tag; null when every archived change is in range. until — null for the working tree.
  • release — { "version", "date" } with --release, else null.
  • entries — in display order. text is the item as written, **BREAKING** marker included. source is release_note, or what_changes for a change archived without a release note.
  • markdown — the entries rendered as Keep a Changelog.
  • written — with --write, { "path", "action" }, action being created, updated or unchanged; else null.

Warnings in status: release_note_missing, release_note_invalid, release_note_inconsistent, not_a_git_repository, archived_change_unreadable. Error codes: unknown_ref, not_a_git_repository (with --since or --until outside git), invalid_release_version, invalid_date, invalid_argument, changelog_malformed.

new change

{
  "changeName": "add-audit-log",
  "schemaName": "spec-driven",
  "changeRoot": "/home/you/acme-app/_codev/changes/add-audit-log",
  "created": [
    "/home/you/acme-app/_codev/changes/add-audit-log/change.yaml"
  ],
  "status": []
}

list

{
  "changes": ["add-audit-log"],
  "root": "/home/you/acme-app",
  "status": []
}

With --specs, the array is named specs and lists capability paths.

codev search --json:

{
  "root": "/home/you/acme-app",
  "query": "decision seal",
  "language": "en",
  "results": [
    {
      "kind": "requirement",
      "id": "decisions::Body seal recorded by the CLI",
      "capability": "decisions",
      "requirement": "Body seal recorded by the CLI",
      "excerpt": "The CLI SHALL maintain a `_codev/decisions/seal.yaml` file…"
    },
    {
      "kind": "decision",
      "id": "project/0003",
      "decision": "0003",
      "title": "The planning folder is hidden",
      "origin": "project",
      "status": "superseded",
      "inEffect": false,
      "supersededBy": "project/0009",
      "excerpt": "…"
    }
  ],
  "archived": [
    { "change": "2026-09-09-enforce-decision-immutability", "excerpt": "…" }
  ],
  "status": []
}

language is the language the words were stemmed in. A result carries the fields of its kind only; archived is present only with --archive. Inside a result, status is the decision’s status, not the root array of errors.

show

codev show --json:

{
  "root": "/home/you/acme-app",
  "capability": "decisions",
  "requirement": {
    "name": "Creating a decision through the CLI",
    "text": "### Requirement: Creating a decision through the CLI\n\n…"
  },
  "status": []
}

codev show <capability> carries requirements, the requirement names, and purpose instead of requirement. A failure carries capability: null and its code in status.

status

{
  "changeName": "add-audit-log",
  "schemaName": "spec-driven",
  "planningHome": "/home/you/acme-app",
  "changeRoot": "/home/you/acme-app/_codev/changes/add-audit-log",
  "applyRequires": ["tasks"],
  "isPlanningComplete": false,
  "artifacts": [
    {
      "id": "proposal",
      "outputPath": "proposal.md",
      "status": "ready",
      "requires": [],
      "missingDeps": []
    },
    {
      "id": "specs",
      "outputPath": "specs/**/*.md",
      "status": "blocked",
      "requires": ["proposal"],
      "missingDeps": ["proposal"]
    }
  ],
  "update": {
    "current": "0.5.0",
    "latest": "0.6.0",
    "url": "https://github.com/mairistem/codev/releases/tag/v0.6.0",
    "available": true,
    "snoozed": false
  },
  "versionRequirement": {
    "requirement": ">=0.5",
    "satisfied": true
  },
  "status": []
}

An artifact’s status is done, ready, blocked or skipped. planningHome is the project root; skills use it rather than assuming the current directory.

update is present when the latest codev release is known: current is the running version, latest the latest release, url its release page, available whether latest is newer, and snoozed whether codev self-update --snooze silenced it. It is absent when the check is disabled (CI, CODEV_NO_UPDATE_CHECK=1) or has never succeeded. versionRequirement is present when _codev/config.yaml sets codev_version: requirement is its value, satisfied whether the running version matches it. Both objects are additive: a consumer that ignores them reads the document as before.

self-update

codev self-update --json, which implies --yes:

{
  "current": "0.5.0",
  "latest": "0.6.0",
  "url": "https://github.com/mairistem/codev/releases/tag/v0.6.0",
  "action": "updated",
  "installMethod": "standalone",
  "path": "/home/you/.local/bin/codev",
  "hint": null,
  "projectUpdated": true,
  "status": []
}

action is updated, up_to_date, available (with --check), snoozed, nothing_to_snooze or managed_elsewhere. installMethod is standalone, cargo, build or package_manager; for the last three, hint holds the command that upgrades codev. latest and url are null when unknown. Failures keep this shape and carry their code in status — see the codes.

instructions

{
  "changeName": "add-dark-mode",
  "schemaName": "spec-driven",
  "artifact": "design",
  "description": "Technical approach and decisions",
  "resolvedOutputPath": "/home/you/acme-app/_codev/changes/add-dark-mode/design.md",
  "instruction": "Write the document that explains HOW to implement the change.\n…",
  "template": "# Design: <change title>\n…",
  "language": "en",
  "context": [
    { "origin": "path:~/src/acme-standards", "text": "All services log in JSON." },
    { "origin": "project", "text": "TypeScript monorepo." }
  ],
  "rules": [
    { "origin": "project", "text": "Cite the decisions that constrain the approach." }
  ],
  "dependencies": [
    { "id": "proposal", "path": "/home/you/acme-app/_codev/changes/add-dark-mode/proposal.md", "done": true }
  ],
  "unlocks": ["tasks"],
  "decisions": [
    {
      "id": "0003",
      "qualifiedId": "project/0003",
      "title": "Use SQLite for persistence",
      "status": "accepted",
      "tags": [],
      "path": "_codev/decisions/0003-use-sqlite-for-persistence.md",
      "origin": "project"
    }
  ],
  "related": [
    {
      "capability": "decisions",
      "requirement": "Creating a decision through the CLI",
      "excerpt": "`codev decision new <title>` SHALL create a new ADR in the project…"
    }
  ],
  "skipped": false,
  "role": {
    "id": "architect",
    "name": "Architect",
    "kind": "artifact",
    "at": "plan.write",
    "steps": ["plan.write"],
    "artifact": "design",
    "domains": [],
    "question": "How will it be built?",
    "when": "always",
    "whenOrigin": "default",
    "activatedBy": "always",
    "disableable": false,
    "knowledge": null,
    "doneWhen": [
      { "origin": "schema:spec-driven", "text": "each decision names the alternative it rejects and why" },
      "…"
    ]
  },
  "status": []
}
FieldMeaning
resolvedOutputPathWhere to write; may be a glob such as …/specs/**/*.md
instruction, templateFrom the schema; null when the schema defines none
languageThe artifact language, en by default
relatedThe existing requirements the change likely touches, ranked against the proposal’s Why and What Changes, at most 10, each with capability, requirement and excerpt — for the artifacts that require the proposal directly (specs, design), once it is written; an empty array otherwise
context, rulesBlocks ordered from the most general source to the project, each with its origin (project, path:<path> or git:<url>)
dependenciesThe artifacts this one requires, with their path and whether they are done
unlocksArtifacts that become writable once this one exists
decisionsThe decisions in effect — filled for design, empty for other artifacts
skippedtrue when skip_specs disables this artifact: it must not be written
roleThe role that owns the artifact, in the shape of codev roles; null when the schema declares none

A failure keeps this shape, with language still set — the configured language, or en when the configuration cannot be read — and the other fields null or empty.

validate

{
  "root": "/home/you/acme-app",
  "items": [
    {
      "kind": "change",
      "name": "add-audit-log",
      "path": "_codev/changes/add-audit-log",
      "findings": [
        {
          "path": "_codev/changes/add-audit-log/change.yaml",
          "line": 1,
          "severity": "error",
          "code": "zero_delta_without_marker",
          "message": "no delta file under `specs/` and `skip_specs: true` is not declared; add a delta or set `skip_specs: true` in change.yaml"
        }
      ]
    }
  ],
  "hasWarnings": false,
  "status": []
}

kind is change, spec, decisions or config — the last one only when _codev/config.yaml holds keys this codev does not know (see Unknown keys). Findings are reported in items, not in status: status only carries a failure of the command itself. See Validation codes.

sync and archive

{
  "changeName": "add-dark-mode",
  "root": "/home/you/acme-app",
  "updated": [],
  "created": ["/home/you/acme-app/_codev/specs/ui/theme/spec.md"],
  "unchanged": [],
  "deleted": [],
  "movedTo": "/home/you/acme-app/_codev/changes/archive/2026-09-30-add-dark-mode",
  "status": []
}

codev sync --json returns the same document without movedTo. deleted lists main specs removed by a change that retires a capability.

review

{
  "changeName": "add-sessions",
  "path": "_codev/changes/add-sessions/review.md",
  "exists": true,
  "format": 1,
  "steps": [
    {
      "step": "plan.challenge",
      "recorded": true,
      "activeRoles": ["skeptic", "security"],
      "roles": [
        { "role": "skeptic", "state": "no-finding", "fallback": null, "credited": ["R-security-1"] },
        { "role": "security", "state": "findings", "fallback": null, "credited": [] }
      ],
      "mode": "isolated",
      "summarized": []
    },
    {
      "step": "code.review",
      "recorded": false,
      "activeRoles": ["newcomer", "security"],
      "roles": [],
      "mode": null,
      "summarized": []
    }
  ],
  "findings": [
    {
      "id": "R-security-1",
      "title": "Session tokens are stored in clear",
      "role": "security",
      "step": "plan.challenge",
      "line": 13,
      "severity": "high",
      "confidence": "high",
      "reported": true,
      "location": "design.md#Decision: Sessions live in the database",
      "evidence": "The session token is stored in the `sessions` table.\n",
      "recommendation": "Store a SHA-256 of the token and compare digests.",
      "status": "disputed",
      "awaiting": "human",
      "history": [
        { "status": "open", "by": "security", "note": null, "ref": null, "to": null },
        { "status": "disputed", "by": "architect", "note": "Tokens expire after 5 minutes.", "ref": null, "to": null },
        { "status": "disputed", "by": "security", "note": "Five minutes is enough to replay a stolen token.", "ref": null, "to": null }
      ],
      "raisedBy": ["security", "skeptic"]
    }
  ],
  "issues": [],
  "archive": {
    "ready": false,
    "blockers": [
      { "code": "review_step_missing", "message": "the review record has no `## code.review` section, while roles were active at it" },
      { "code": "review_unresolved", "message": "R-security-1 (Session tokens are stored in clear) is high and still disputed; fix it, or a human accepts the risk or defers it" }
    ]
  },
  "status": []
}
FieldMeaning
existsfalse without review.md; format, findings are then empty or null
steps[].activeRolesThe roles active at the step for the change, as codev roles --at <step> --change <name> returns them
steps[].roles[].statefindings, no-finding, disabled, empty (a section with nothing usable), or missing (an active role without a section, in a recorded step)
steps[].roles[].fallbackThe role’s Fallback: line — why it reviewed inline in an isolated review — or null
steps[].roles[].creditedThe ids of other roles’ findings of the step whose raised_by names this role
steps[].modeThe step’s Mode: line, inline or isolated, or null when not written
steps[].summarizedThe step’s Summarized: lines, in file order
findings[].raisedByEvery role that raised the finding, its own first: its raised_by, or its role alone
findings[].reportedtrue when the confidence is high: the skills present only those
findings[].statusThe last history entry’s status
findings[].awaitingWho acts next: author (open), reviewer (a fix to verify, a dispute to answer), human (a dispute the reviewer maintained), or null
issuesThe record’s defects, in the shape of validate’s findings, with the review_* codes
archive.blockers[].codereview_record_missing, review_step_missing, review_unresolved or review_format_unsupported

The exit status is 1 only when issues holds an error. Fields the file leaves out or gets wrong are null.

roles

codev roles --at plan.challenge --change add-dark-mode --json:

{
  "changeName": "add-dark-mode",
  "schemaName": "spec-driven",
  "at": "plan.challenge",
  "language": "en",
  "stacks": { "detected": ["TypeScript", "JavaScript"], "filter": "detected" },
  "diff": {
    "available": true,
    "reason": null,
    "base": "origin/main",
    "files": 14,
    "scanned": 11,
    "skipped": { "lockfile": 1, "prose": 2 },
    "truncated": false
  },
  "suggestions": [
    {
      "domain": "user-interface",
      "state": "ticked",
      "justification": null,
      "matchCount": 6,
      "matches": [
        { "source": "accessibility", "kind": "paths", "trigger": "**/*.{html,htm,css,scss,sass,less,jsx,tsx,vue,svelte,astro}", "path": "web/src/theme.css", "line": null },
        "…"
      ]
    },
    {
      "domain": "performance",
      "state": "justified",
      "justification": "the cache is the browser's, not ours",
      "matchCount": 1,
      "matches": [
        { "source": "performance", "kind": "patterns", "trigger": "(?i)\\b(cache|caching|memoi[sz]e|lru)\\b", "path": "web/src/theme.ts", "line": 12 }
      ]
    }
  ],
  "roles": [
    {
      "id": "skeptic",
      "name": "Skeptic",
      "kind": "step",
      "at": "plan.challenge",
      "steps": ["plan.challenge"],
      "artifact": null,
      "domains": [],
      "question": "Would the plan survive a reviewer who did not write it?",
      "when": "always",
      "whenOrigin": "project",
      "activatedBy": "project",
      "disableable": true,
      "knowledge": "## Signals\n\nPlanning smells — each one is a question to raise, not a verdict.\n…",
      "doneWhen": [
        { "origin": "built-in", "text": "**Need** — does the change solve the Why? Is there a simpler solution, or one without code?" },
        "…",
        { "origin": "project", "text": "The rollback plan is stated" }
      ]
    },
    {
      "id": "accessibility",
      "name": "Accessibility",
      "kind": "step",
      "at": "plan.challenge",
      "steps": ["plan.challenge", "code.review"],
      "artifact": null,
      "domains": ["user-interface"],
      "question": "Can everyone use what this change adds, with a keyboard or assistive technology?",
      "when": "on_domain",
      "whenOrigin": "default",
      "activatedBy": "domain:user-interface",
      "disableable": true,
      "knowledge": "## Scope\n\nLook at the user interface the change adds or modifies…",
      "doneWhen": [
        { "origin": "built-in", "text": "Every interactive element is reachable and operable with the keyboard alone, in a logical focus order, with a visible focus" },
        "…"
      ]
    }
  ],
  "disabled": [{ "id": "newcomer", "name": "Newcomer", "whenOrigin": "project" }],
  "review": {
    "mode": "isolated",
    "origin": "project",
    "material": {
      "limitBytes": 163840,
      "totalBytes": 18342,
      "summarized": false,
      "files": [
        { "path": "_codev/changes/add-dark-mode/design.md", "bytes": 6120, "treatment": "full" },
        "…"
      ]
    }
  },
  "status": []
}
FieldMeaning
changeNameThe change given with --change; null without it
schemaNameThe schema the artifact roles come from
atThe step given with --at; null lists every role, active or not
stacksThe languages detected from the project’s dependency manifests (detected: Rust, TypeScript, JavaScript, Python, Go, Java) and the filter applied to the knowledge’s By stack part: detected, none-detected (everything kept) or all-stacks (--all-stacks)
diffWith --change, the change’s diff: available, reason when it is not, the default branch base, the files changed, the files scanned by the patterns, the files skipped per category (planning, vendored, lockfile, generated, binary, prose, large), and truncated when a cap was reached; null without --change
suggestionsWith --change, the domains the diff suggests, in the order of the domains list: state is ticked, justified (with its justification) or unticked; matchCount counts the matches and matches lists the first five, each with its source (the role, or project), kind (paths, manifests, patterns), trigger as written, path, and line for a pattern; empty without --change
roles[].nameThe display name in the configured language, English when the role has none in it
roles[].kindstep, or artifact with the artifact’s id in artifact
roles[].atThe step given with --at, otherwise the role’s first step; plan.write for every artifact role
roles[].stepsEvery step the role serves, in workflow order: an expert serves plan.challenge and code.review
roles[].domainsThe domains that activate an expert, such as ["personal-data"]; empty for the other roles
roles[].when, roles[].whenOriginalways, never or on_domain, set by default, project or change
roles[].activatedByWhy the role is active: always, project, change, or domain:<name> for an expert whose domain the proposal ticks; null when it is inactive
roles[].disableablefalse for the artifact roles, the analyst and the developer
roles[].knowledgeThe role’s knowledge, as markdown in the sections Scope, Signals, By stack, References and Reporting, for an active role that has some, its By stack part filtered as stacks.filter says; null otherwise
roles[].doneWhenThe role’s criteria, then the project’s, each with its origin: built-in, schema:<name> or project
disabledWith --at, the roles serving the step that the configuration turned off — their activation, once the project’s then the change’s settings are applied, is never — each with id, name and whenOrigin (project or change, the file whose setting won). The skills write Disabled by configuration. for them in the review record without a second call. Empty without --at; an expert whose domain is not ticked is inactive, not disabled
review.mode, review.originThe review mode in effect, inline or isolated, set by default, project or change
review.materialWith --change at plan.trace, plan.challenge or code.review, what the reviewers read: the change’s planning files but change.yaml and review.md at the plan steps, the diff’s files at code.review — no planning, vendored, generated, lock or binary file, no symbolic link; a deleted file counts 0 bytes. Each file has its bytes and its treatment: full, or summarize once the files taken from the smallest stop fitting in limitBytes (160 KiB). null otherwise, and at code.review without a diff. A file left out because its size cannot be read or its name holds a control character is named by a review_material_incomplete warning in status

With --at, roles holds only the active roles, possibly none: the step is then skipped. Without --change, no proposal is read, so the experts are inactive. A failure — unknown_step, unknown_role, invalid_role_activation, role_not_disableable — keeps this shape, with roles, disabled and suggestions empty, stacks, diff and review null, and language set as for instructions; an invalid review mode fails with invalid_review_mode. A project trigger that cannot be used is left out with an invalid_trigger warning in status.

schemas

{
  "schemas": [
    { "name": "spec-driven", "origin": "built-in", "flow": ["proposal", "specs", "design", "tasks"] }
  ],
  "root": "/home/you/acme-app",
  "status": []
}

origin is project or built-in. A project schema that cannot be used is left out of schemas, with a warning schema_unusable in status. A project schema whose name: differs from its folder is listed under its folder name, with a warning schema_name_mismatch.

decision

codev decision list --json returns { "root", "decisions": [...], "status" }, and codev decision show --json returns { "root", "decision", "content", "status" }, where content is the full Markdown of the file. A decision is:

{
  "id": "0001",
  "qualifiedId": "project/0001",
  "title": "Use PostgreSQL for persistence",
  "status": "superseded",
  "date": "2026-09-30",
  "tags": [],
  "supersedes": [],
  "deviatesFrom": [],
  "path": "…/_codev/decisions/0001-use-postgresql-for-persistence.md",
  "origin": "project",
  "inEffect": false,
  "supersededBy": "project/0003"
}

deviatedBy is added for an inherited decision set aside by a local deviation. origin is project, path:<path> or git:<url>. path is relative to the project for a decision inside it, absolute otherwise.

The commands that create or seal decisions return:

CommandFields besides root and status
decision newdecision, path, bodySha256 (only with --status accepted)
decision acceptdecision, path, bodySha256, superseded
decision supersedenewDecision, newPath, oldId, oldQualifiedId, oldPath
decision sealseal (id, bodySha256, sealedAt), wasNoop
decision deviatedecision, path, targetQualifiedId
decision promotedecision, path, sourceChange, designPath

bodySha256 is present only when the command sealed the decision: decision supersede, decision deviate and decision promote create a proposed decision and seal nothing. For decision supersede, oldId, oldQualifiedId and oldPath name the decision that accepting the new one will supersede; it is not modified. superseded lists the predecessors that decision accept set to superseded — each with its id, qualifiedId and path — and is empty when the decision supersedes nothing.

For example, codev decision accept 0002 --json for a decision created by codev decision supersede 0001 "Use SQLite":

{
  "root": "/home/you/acme-app",
  "decision": {
    "id": "0002",
    "qualifiedId": "project/0002",
    "title": "Use SQLite",
    "status": "accepted",
    "date": "2026-09-30",
    "tags": [],
    "supersedes": [
      "0001"
    ],
    "deviatesFrom": [],
    "path": "_codev/decisions/0002-use-sqlite.md",
    "origin": "project",
    "inEffect": true,
    "supersededBy": null
  },
  "path": "/home/you/acme-app/_codev/decisions/0002-use-sqlite.md",
  "bodySha256": "sha256:c8873b83c178dbf8434045f43a722911b9d9913ee9f13915ccda893539b788c1",
  "superseded": [
    {
      "id": "0001",
      "qualifiedId": "project/0001",
      "path": "/home/you/acme-app/_codev/decisions/0001-use-postgresql.md"
    }
  ],
  "status": []
}

A refused acceptance keeps the same shape, with decision and path set to null, superseded empty and the code in status: unknown_decision_id, cannot_accept_inherited, decision_not_proposed, cannot_supersede_inherited or predecessor_not_accepted.

sources

codev sources list --json returns { "root", "sources": [...], "status" }, where a source is:

{
  "type": "git",
  "address": "git@github.com:acme/codev-standards.git",
  "state": "locked",
  "gitRef": "main",
  "sha": "12958274cbed0eb66985f57d3272c6d3134b672d",
  "resolvedPath": "/home/you/.cache/codev/content/12958274cbed0eb66985f57d3272c6d3134b672d"
}

type is path or git; state is one of resolved, unreadable, unlocked, locked, needs_update. gitRef, subpath, sha and resolvedPath are omitted when they do not apply.

codev sources show --json returns { "source", "filesExposed", "root", "status" }. codev sources update --json returns { "root", "changes", "lockWritten", "status" }, where each change has a kind (added, moved or unchanged), url, gitRef, from (for moved) and to.

FAQ and troubleshooting

General

Does codev send my code to a model?

No. The codev binary never calls a language model. It uses the network only to fetch inherited git sources (codev sources update) and to look for a newer codev release (codev status, codev self-update). Your agent — Claude Code — does the writing, with the same access it has in any other session.

Does codev check for updates?

Yes, and only that. At most once every 24 hours, codev status sends one anonymous HTTPS request to GitHub’s public API (https://api.github.com/repos/mairistem/codev/releases/latest) to read the latest release number, and caches it in ~/.cache/codev/update-check.json. Nothing about you or your project is sent; there is no telemetry. A failed request is silent and is not retried before the next day.

The check never runs when CI is set, so pipelines stay reproducible. To turn it off on your machine, set CODEV_NO_UPDATE_CHECK=1. Nothing is ever installed without your consent: updating takes codev self-update, or your answer “Update now” in a skill.

Can I use codev without Claude Code?

The CLI works on its own: you can create changes, write the artifacts yourself following codev instructions, validate, sync and archive. The skills, which do the writing for you, target Claude Code only.

Should I commit _codev/ and .claude/skills/?

Yes. _codev/ is the record of your specs, decisions and changes; commit it entirely, including _codev/decisions/seal.yaml and _codev/codev.lock. Committing .claude/skills/ gives everyone on the team the same skills without running codev init.

Does a small fix need a full change?

Every change goes through the same cycle, but the plan can be small: a one-line proposal, a one-requirement delta, a two-task list. For a change that has no behavioral impact, set skip_specs: true in its change.yaml.

Can I keep codev out of CLAUDE.md, CI or the pull request template?

Yes. Pass --no-claude-md, --no-ci or --no-pr-template to codev init, or --no-integration for all three. codev update never adds them later. To keep the workflow but own it, delete its first line, # codev:managed: codev then leaves the file alone. To remove codev’s text from CLAUDE.md or the template, delete the block between the codev:begin and codev:end markers. See Repository integration and codev doctor.

Should my reviewers work in isolation?

By default (inline), the skill that wrote the plan or the code also reviews it, one role after the other, in the same conversation. With review: { mode: isolated } in _codev/config.yaml, each reviewing role works alone as a Claude Code sub-agent that never sees the conversation, and the skill then merges what they found. It costs more — each reviewer reads the material — and its benefit is not measured yet, so start with the changes where a fresh look matters most: set review: { mode: isolated } in those changes’ change.yaml, or project-wide once you have seen the difference. Run codev update after changing the project’s mode. See Inline or isolated review.

How do I share this documentation?

codev docs --write ~/Downloads/codev-manual.html

The file is self-contained — inline CSS, no external resources — and can be sent by email or dropped into a wiki.

Troubleshooting

no codev project found

error: no codev project found from /home/you — run `codev init` at the project root

codev looks for _codev/ in the current directory and its parents. Run the command inside your project, or initialize it with codev init.

The skills do not appear in Claude Code

Claude Code discovers skills when a session starts. After codev init or codev update, restart Claude Code or open a new session. Check that .claude/skills/codev-*/SKILL.md exist at the root of the project you opened.

codev update leaves a skill in place

  Left in place because edited by hand — rerun with --force to overwrite:

That skill was edited by hand — its content no longer matches its checksum — and codev does not discard your work. Keep the edit and ignore the message, or run codev update --force to regenerate it (check git diff first). A skill generated before checksums existed is preserved the same way until one codev update --force gives it its checksum.

A reviewer’s sub-agent fails

In isolated review, a sub-agent that fails or is stopped is run once more; if it fails again, that role reviews inline and the record says why on a Fallback: line under the role. Nothing is lost: the review is done, only not in isolation for that role. If every role falls back, check that Claude Code can start sub-agents (the Agent tool) and that codev doctor reports the skills current for the review mode — skills_review_mode means codev update has not run since the mode changed.

codev validate reports zero_delta_without_marker

The change has no spec delta under specs/. Either write the delta — the behavior the change adds or modifies — or, if the change truly has no behavioral impact, add skip_specs: true to its change.yaml.

codev validate reports decision_seal_mismatch

The body of a sealed decision was modified — by hand, or by a formatter. Accepted decisions are immutable:

  • Restore the original body (git diff shows what changed); the seal is valid again.
  • Or, if the edit was deliberate, reseal it: codev decision seal <ID> --force.

To write a decision before sealing it, keep it proposed — as codev decision new, supersede, deviate and promote create it — and run codev decision accept <ID> once its text is final. A decision created with codev decision new --status accepted is sealed straight away, with the template’s placeholder text.

To change what a decision says, supersede it with codev decision supersede <ID> "<new title>" instead, write the new decision, then accept it.

To keep formatters away from decisions, exclude _codev/decisions/ in their configuration.

codev decision accept reports predecessor_not_accepted

The decision you are accepting lists, in supersedes, a decision that is no longer accepted — usually because another decision superseded it after yours was created. Nothing was written. Run codev decision list to see which decision is now in effect, then either point supersedes at that decision in the frontmatter of yours, or drop yours if it has become redundant. codev decision supersede refuses a decision that is not accepted with the same code.

codev validate reports decision_missing_frontmatter

Every .md file in _codev/decisions/ is parsed as a decision. Move other Markdown files, such as a README, out of that folder.

A spec archived with an earlier codev holds a cut requirement

In codev 0.6.1 and earlier — builds made before this fix — archiving a change that both modified the last requirement of a spec and added requirements could write the added ones in the middle of a line of the modified one: the spec then holds the start of that requirement, the added ones, and its end glued after them. codev validate does not detect it, and syncing or archiving the change again does not repair it. To check, look at the diff of each archive of a change whose delta modified a spec’s last requirement and added requirements; to repair, put the requirement back whole by hand, or with a new change whose MODIFIED delta gives its full text.

Sync or archive refuses a change

error: change `add-dark-mode` has errors; run `codev validate add-dark-mode` for details

With --json, the error code is validation_failed. Run the suggested codev validate command, fix the findings, and sync or archive again. An archive refused because a MODIFIED requirement does not exist in the main spec means the name differs from the one in the main spec: fix the name, or use ADDED if the requirement is new.

codev validate reports rename_source_missing

The name after FROM: in ## RENAMED Requirements matches no ### Requirement: heading of the main spec. It must match exactly, whether you write the bare name or the full heading in backticks:

- FROM: `### Requirement: The chosen theme is remembered`
- TO: `### Requirement: The chosen theme follows the user`

codev validate reports delta_unexpected_heading

A ### heading in a delta section is not a requirement heading — for example ### Notes, or a keyword in a language codev does not know. codev reads ### Requirement: and its French equivalent ### Exigence :; see Artifact language.

/codev-propose ignores my ticket

  1. mcp.jira_tool was not set in _codev/config.yaml when the skills were generated: .claude/skills/codev-propose/SKILL.md then reads “(Jira MCP not configured)” where the tool name should be. Add the key, then run codev update --force.
  2. The tool is configured but not available in the current Claude Code session — wrong name, server not connected, expired login. The skill tells you, and writes the proposal from your request alone.

See Jira and other MCP servers.

codev init warns inherit_pin_failed

A git source given with --inherit was declared but could not be pinned: git is missing, the network or your credentials failed, or the ref does not exist (the default is main; a repository whose default branch is master needs …/repo.git@master). Fix the cause — or the ref: in _codev/config.yaml — then run codev sources update.

codev init warns managed_section_malformed

CLAUDE.md or the pull request template has a <!-- codev:begin line without a matching <!-- codev:end -->, or several of them. codev left the file untouched. Keep exactly one pair of markers, or remove them all to let codev init append a fresh section.

A git source is unlocked or needs_update

Run codev sources update. unlocked means the source has never been resolved; needs_update means it is pinned in codev.lock but missing from your local cache, typically on a fresh machine.

A teammate’s codev fails on the configuration

Their codev is older than your _codev/config.yaml: the file holds a key their version does not know.

  • codev 0.5 and earlier reject any unknown key: every command fails with invalid, naming the key. They need to update — codev self-update from a recent version, otherwise the installer of Installation.
  • More recent versions warn with unknown_config_key instead and keep working; the warning quotes your codev_version and points to codev self-update. An unknown key inside an inherits entry or changelog still fails with invalid, quoting codev_version.

To make the message explicit for everyone, raise codev_version whenever you add a key that only recent versions know. See Unknown keys.

unknown_config_key

_codev/config.yaml holds a key this codev does not know: it is ignored and the rest of the configuration applies. Either the key comes from a newer codev (run codev self-update, or the version codev doctor names in its codev_version check), or it is a typo, such as shema for schema: correct it. codev validate --strict fails until then. When codev doctor suggests codev self-update --version <X.Y.Z>, your codev is newer than the project’s codev_version allows, and that command installs a version that satisfies it.

codev self-update reports update_checksum_mismatch

The downloaded archive does not match its line in the release’s SHA256SUMS, or that line is missing. Nothing was installed. Retry later — a proxy may have altered the download — and, if it persists, report it: it is the check that protects you from a tampered archive.

codev self-update reports update_not_writable

codev cannot write in the folder of its binary, for example /usr/local/bin owned by root. Reinstall codev in a folder you own (install.sh uses ~/.local/bin), or run the command with the rights that folder needs.

codev self-update says codev is managed elsewhere

Your binary was installed by cargo install, built from a clone, or installed by a package manager: codev leaves it to that tool and prints the command to run, such as cargo install --path crates/codev-cli from an up-to-date clone.

codev: command not found

The install folder is not on your PATH. See Check the installation.

Architecture

This chapter is for contributors: how the code is organized, and why. The decisions behind it, with their context and the alternatives considered, are recorded as ADRs in _codev/decisions/ — codev is developed with codev. This chapter summarizes and connects them.

A pure core, an imperative shell

codev follows one principle: deciding is not executing.

  • Everything that is pure lives in codev-core: the domain model, schemas, the artifact graph, the parsers, validation rules, merging, and the computation of plans. No std::fs, no std::env, no clock, no network.
  • Everything that needs the outside world lives above it, behind a port.

The dependency rule is not a folder convention: it is the crate graph, and Cargo refuses to compile a cycle. The compiler enforces it, without facade interfaces or a dependency-injection container.

The crate graph

codev-cli ──▶ codev-agents ──▶ codev-engine ──▶ codev-core
    │                               ▲                ▲
    ├───────────────────────────────┘                │
    └────────────────────────────────────────────────┘
CrateRoleI/O
codev-coreModel, schemas, artifact graph, parsers, validation rules, merge, plansNone
codev-engineDisk layout, configuration, schema resolution, decisions index, inherited sources, plan executionThrough ports
codev-agentsThe AgentTarget trait and its Claude Code implementation; the workflow catalogThrough ports
codev-cliArgument parsing, human rendering, the versioned JSON contract, prompts, embedded docsYes — it is the shell

codev-agents also depends on codev-core, and codev-cli on every crate.

A module becomes a crate only when it has earned it — a clean test boundary, or an external consumer. Splitting earlier only produces refactoring churn.

Plans, not side effects

The core never touches the disk. It returns a plan of effects — files to create or overwrite, files to delete, folders to move — and the shell executes it. init, new change, sync, archive, the skill installation and the decision commands all work this way.

This buys several things at once: the whole plan is validated before the first write, merges are tested without temporary files, and dry runs or previews come for free.

Ports

There are four ports, only for effects:

PortWhy
FileSystemMakes init, sync and archive testable in memory
ClockArchive and decision dates must be deterministic in tests
EnvHome directory, XDG_CACHE_HOME, locale variables
ProcessRunnerDriving git for inherited git sources

What codev does not do: no repository trait hiding std::fs, no one-method *UseCase structs, no Arc<dyn Trait> by default. Traits serve boundaries that are genuinely open (AgentTarget, Rule), generics serve the rest, and enums model closed sets.

The two risks the architecture guards against

  1. A destructive Markdown rewrite. A MODIFIED delta that reformats the file or loses content it does not mention. The parsers therefore keep the original byte spans of every block, so the merge rewrites one block without touching the rest.
  2. Drift of the JSON contract. The JSON output is a public API, consumed by skills already installed on users’ machines. Domain types therefore do not derive Serialize: codev-cli has a dedicated contract module whose types translate the domain, with tests that pin the field names. It is the project’s only DTO boundary, and it has a reason to exist.

Extension points

  1. AgentTarget — one implementation per agent tool. Claude Code today; another tool can be added without touching the core.
  2. Rule — one validation rule per implementation, registered in a list.
  3. Schemas, templates and workflows as data — schema.yaml, the templates and the skill bodies live in assets/ and are embedded at build time. Improving an instruction never requires touching Rust code.

Where things live

PathContent
assets/schemas/spec-driven/The built-in schema and its templates
assets/templates/decision.mdThe ADR template
assets/workflows/*.mdThe body of each skill
crates/codev-agents/src/workflows.rsThe workflow catalog: descriptions, allowed-tools, defaults
crates/codev-cli/src/contract.rsThe JSON contract, version 1
crates/codev-cli/build.rsEmbeds the documentation chapters listed in docs/<lang>/src/SUMMARY.md
_codev/codev’s own specs, decisions and changes

Architecture decisions

ADRDecision
0001Functional core, imperative shell: the core returns plans, the shell executes them
0002The crate graph enforces the dependency rule; four ports for effects
0003The planning root is _codev/, visible
0004One identity for a skill and its slash command; no separate command files
0005Inherited sources are read-only and pinned by commit, not shared writable stores
0006serde_norway for YAML, the maintained fork of serde_yaml

Conventions

  • Errors. thiserror and typed errors in library crates; anyhow only in codev-cli, where errors are translated into the status array of the JSON contract.
  • Comments are in English and explain why. A comment that paraphrases the code is noise.
  • Tests. The core is tested with pure unit tests; the engine with an in-memory FileSystem and fixed Clock and Env; the JSON contract with tests on its field names and shapes.