CLI reference
The selvedge binary is your interface to the SQLite store. Every read command supports
--json for machine-readable output. Relative time strings (15m, 24h, 7d, 5mo,
1y) and ISO 8601 timestamps are accepted everywhere --since shows up.
Commands at a glance
Section titled “Commands at a glance”selvedge init [--path PATH] Initialize Selvedge in a projectselvedge setup Interactive first-run wizardselvedge prompt [--install FILE] Print canonical agent-instructions blockselvedge watch Live-tail new eventsselvedge status Recent activity summaryselvedge doctor [--json] Health checkselvedge verify [--strict] [--json] Correctness checks against the storeselvedge diff ENTITY [--limit N] History for an entity / prefixselvedge blame ENTITY Most recent change + contextselvedge history [...filters] Browse all historyselvedge changeset [ID|--list] Events grouped by changesetselvedge search QUERY [--limit N] Full-text searchselvedge prior-attempts [ENTITY] Prior attempts on an entity + outcomeselvedge stale [...filters] Dated decisions due for a revisitselvedge stats [--since SINCE] Tool-call coverage reportselvedge install-hook [--path PATH] Install git post-commit hookselvedge backfill-commit --hash HASH Backfill git_commit on recent eventsselvedge import PATH Import migrations (SQL / Alembic) or an Agent Trace fileselvedge export [--format json|csv|agent-trace] Export history (Agent Trace v0.1.0 since 0.3.9)selvedge log ENTITY CHANGE_TYPE Manually log a changeselvedge migrate-paths [--apply] Re-canonicalize stored entity pathsselvedge backup [--output FILE] Snapshot the store via VACUUM INTOselvedge prune [--days N] Trim old tool_calls telemetry (90-day default)Lifecycle
Section titled “Lifecycle”selvedge init [--path PATH]
Section titled “selvedge init [--path PATH]”Creates .selvedge/selvedge.db in the current directory (or --path). Writes the
schema and registers the bootstrap migration. Idempotent — running on an existing
project is a no-op.
selvedge setup
Section titled “selvedge setup”Interactive first-run wizard. Detects which AI tools you have and walks through every install step in one pass:
- Adds the Selvedge MCP entry to each tool’s config
- Drops the canonical agent-instructions block into the project’s prompt file
- Runs
selvedge initif.selvedge/doesn’t exist - Installs the post-commit hook
Every modified file gets a .bak written next to it before any change reaches disk.
Re-running on an already-set-up project is a no-op (idempotent). Existing-but-different
MCP entries trigger a conflict warning rather than silent overwrite — pass --force to
overwrite, or update by hand.
For CI / devcontainer postCreateCommand:
selvedge setup --non-interactive --yesselvedge prompt [--install FILE]
Section titled “selvedge prompt [--install FILE]”Prints the recommended system-prompt block to stdout. Pipe-friendly:
selvedge prompt | tee -a CLAUDE.md--install <file> installs the block idempotently. The block is sentinel-bracketed
(<!-- selvedge:start --> / <!-- selvedge:end -->) so re-running --install updates
the bracketed region without disturbing anything else in the file.
The block source is selvedge.prompt.PROMPT_BLOCK — a public constant, importable for
templating into your own onboarding flows.
selvedge install-hook [--path PATH] [--window MIN]
Section titled “selvedge install-hook [--path PATH] [--window MIN]”Installs a git post-commit hook that automatically backfills git_commit on Selvedge
events after each commit. Safe to run on repos with existing post-commit hooks (appends
rather than overwrites). Idempotent.
The hook’s --window (default 60 minutes) controls how far back it’ll look for events
to associate with the commit.
Reading
Section titled “Reading”selvedge status
Section titled “selvedge status”Recent activity summary. Surfaces:
- Total events
- Events in the last 24h / 7d / 30d
- Count of events missing
git_commit(nudges you towardinstall-hook) - Last
tool_callsentry timestamp (proxy for “is the agent wired up?”) - MCP wiring detection — distinguishes “installed but agent hasn’t reloaded” from “not installed anywhere” with config-path-aware diagnostics
selvedge doctor [--json]
Section titled “selvedge doctor [--json]”Single-command health check. Each row is PASS / WARN / FAIL / INFO:
- Which DB path is being resolved (and which precedence step matched)
- Whether
.selvedge/exists where you think it does - Whether the schema is at the latest migration version
- Whether the post-commit hook is installed
- Whether the post-commit hook has been failing silently
- Last
tool_callsentry timestamp - Whether
SELVEDGE_LOG_LEVELis set to a recognized value
Exits 1 if any FAIL row is present so doctor can be wired into CI.
selvedge verify [--strict] [--json]
Section titled “selvedge verify [--strict] [--json]”Correctness checks against the Selvedge store, in two tiers:
must_fail— SQLite corruption, schema mismatch, invariant violations (emptyentity_path, unknownchange_type, bad timestamps)should_warn— soft signals (singleton changesets, events past the backfill window with nogit_commit)
Exit 0 when clean or only should-warn rows triggered; exit 1 on any must-fail row.
--strict escalates should-warn rows to failures too, so you can wire selvedge verify
into CI without || true on day one and promote the soft tier once the team is ready.
selvedge watch [--interval N] [--since] [--entity] [--project] [--agent] [--json]
Section titled “selvedge watch [--interval N] [--since] [--entity] [--project] [--agent] [--json]”Polls the SQLite store at --interval (default 1s) and prints each new event as it
lands, Rich-formatted. Filters mirror selvedge history exactly. --json emits one
compact JSON object per line for piping into jq. Ctrl-C exits cleanly.
WAL mode means the polling SELECT never blocks the writer; runtime cost is one indexed query per second while the command is running.
selvedge diff ENTITY [--limit N]
Section titled “selvedge diff ENTITY [--limit N]”History for an exact entity (users.email) or prefix (users returns all
users.*). Newest first. --json for machine-readable output.
selvedge blame ENTITY
Section titled “selvedge blame ENTITY”Most recent change for an exact entity, plus full context — agent, timestamp, commit, reasoning. The query everyone runs first.
On miss, returns a stable shape with every field empty and error populated with the
“no history found” message — easier to type-check without branching.
selvedge history [...filters]
Section titled “selvedge history [...filters]”Browse all history with combined filters:
--since SINCE 15m | 24h | 7d | 5mo | 1y | ISO 8601--entity ENTITY exact or prefix match--project PROJECT limit to a project name--changeset CS limit to a changeset--summarize one-line-per-event summary instead of full panels--limit Nselvedge changeset [ID | --list]
Section titled “selvedge changeset [ID | --list]”Without an ID, lists all changesets with summary stats (event count, agent, time range). With an ID, returns the events grouped under that changeset, oldest-first so you can reconstruct the full scope of a feature.
selvedge search QUERY [--limit N]
Section titled “selvedge search QUERY [--limit N]”Full-text search across reasoning + diff + entity_path. Properly escapes SQL LIKE
wildcards (_, %, \) so selvedge search "stripe_customer_id" won’t accidentally
match stripeXcustomerXid.
selvedge prior-attempts [ENTITY] [--description TEXT] [--all] [--window WHEN] [--limit N]
Section titled “selvedge prior-attempts [ENTITY] [--description TEXT] [--all] [--window WHEN] [--limit N]”Prior change attempts on an entity, each with an inferred outcome — the CLI parity
(new in v0.3.8) for the prior_attempts MCP tool, which shipped in v0.3.7. A thin
presenter over the same get_prior_attempts store, so --json is byte-identical to what
the MCP tool returns and the two surfaces can’t diverge.
Pass an ENTITY positional xor --description TEXT (free-text, when you don’t have
an exact path) — not both. By default only the clear “tried then reverted”
(proximity_high) cases come back; --all widens recall to proximity_low. --window
(e.g. 7d, 60m) maps onto the add→remove proximity window.
selvedge prior-attempts users.auth_token # exact entityselvedge prior-attempts --description "persistent login token"selvedge prior-attempts users.auth_token --all --jsonAn empty result is the normal, good answer — exit 0, nothing clearly tried-and-rejected.
Records on the same coverage counter as the MCP tool, so selvedge stats reflects both
surfaces.
selvedge stale [--entity ENTITY] [--project PROJECT] [--agent AGENT] [--limit N]
Section titled “selvedge stale [--entity ENTITY] [--project PROJECT] [--agent AGENT] [--limit N]”Dated decisions that are due for a revisit — the CLI mirror of the stale_decisions
MCP tool (new in v0.3.8). Surfaces events whose revisit_after has passed and whose
entity is still in active use; pure age never surfaces. Most-overdue-first. --json for
cron / Slack / digest jobs.
selvedge stale # everything past its revisit date and still liveselvedge stale --entity deps/stripe # scope to one entityselvedge stale --json # for cron / morning reportsEach row carries the revisit due date, days overdue, the active-use signals that fired,
and a templated reason. Composes with reporting jobs the same way selvedge digest
(planned for v0.3.16) will.
selvedge stats [--since SINCE]
Section titled “selvedge stats [--since SINCE]”Tool-call coverage report:
- Per-agent breakdown — total calls, log_change calls, coverage ratio
- Missing-reasoning count — events whose stored reasoning fails the quality validator (empty, too short, generic placeholder)
- Recent call history
Catches the case where one agent (e.g. claude-code) is well-instrumented but another (e.g. cursor) is only querying history and never logging changes.
Writing
Section titled “Writing”selvedge log ENTITY CHANGE_TYPE [--diff TEXT] [--reasoning TEXT] ...
Section titled “selvedge log ENTITY CHANGE_TYPE [--diff TEXT] [--reasoning TEXT] ...”Manually log a change. Useful for backfilling, post-hoc annotation, or scripts.
change_type is validated via click.Choice against the canonical set:
add | remove | modify | rename | retype | create | delete |index_add | index_remove | migrateInvalid types are caught at argument parsing with the full list of valid choices.
Other flags: --agent, --commit, --project, --changeset, --rename-from,
--revisit-after.
--revisit-after WHEN (new in v0.3.8) sets a revisit date on the change — an ISO-8601
date or a relative offset (90d, 6mo), normalized like --since. The decision then
surfaces in selvedge stale / the stale_decisions MCP tool once the date passes and
the entity is still in active use:
selvedge log deps/stripe add --reasoning "Pinned to v11 for billing." --revisit-after 180d--rename-from OLD (with CHANGE_TYPE = rename, and the new path as ENTITY)
records the dual-event rename — a rename on the old path and a create on the new
path with metadata.renamed_from set — so history follows the entity:
selvedge log src/auth/session.py::login rename --rename-from src/auth.py::loginselvedge migrate-paths [--apply] [--agent NAME] [--json]
Section titled “selvedge migrate-paths [--apply] [--agent NAME] [--json]”Re-canonicalizes every stored entity_path (strip leading ./, collapse //,
normalize separators, trim — case preserved), so older rows written before v0.3.7
match the canonical form used on every write today.
Dry-run is the default — nothing is written until you pass --apply. A dry run
prints the planned rewrites (old → canonical) and a collisions report: distinct
pre-canonicalization paths that would converge to the same value, i.e. histories the
migration would merge. Inspect those before applying.
selvedge migrate-paths # dry run: rewrites + collisions reportselvedge migrate-paths --apply # write the canonical pathsIdempotent on the event data — re-running after --apply rewrites nothing. Each
--apply run records one audit row in the path_migrations table (surfaced by
selvedge doctor).
Backfill / interop
Section titled “Backfill / interop”selvedge import PATH [--format auto|sql|alembic|agent-trace] [--project NAME] [--dry-run]
Section titled “selvedge import PATH [--format auto|sql|alembic|agent-trace] [--project NAME] [--dry-run]”Parse migration files and backfill schema history.
- Raw SQL DDL —
CREATE TABLE,ALTER TABLE ADD/DROP/RENAME/ALTER COLUMN,DROP TABLE,CREATE/DROP INDEX,RENAME TABLE - Alembic Python migrations —
op.add_column,op.drop_column,op.create_table,op.drop_table,op.alter_column,op.rename_table,op.create_index,op.drop_index,op.execute()(with inline SQL parsing) - Agent Trace (
--format agent-trace, since v0.3.9) — PATH is an Agent Trace JSON/NDJSON file. Round-trips aselvedge export --format agent-tracelosslessly (entity, change type, and reasoning survive indev.selvedgemetadata); foreign producers import best-effort (change_type="modify", empty reasoning).
Directories are walked recursively; files are sorted by name for chronological order. Bulk inserts are wrapped in a single transaction so a long Alembic history imports atomically.
A CREATE TABLE users (id INT, email TEXT) emits a table.create event for users
and a column.add event for each column, so selvedge blame users.email works
even when the column was defined only in the initial schema.
selvedge export [--format json|csv|agent-trace] [--since] [--entity] [--output FILE]
Section titled “selvedge export [--format json|csv|agent-trace] [--since] [--entity] [--output FILE]”Dump change history to JSON or CSV with full filter support.
--format agent-trace (since v0.3.9) emits Agent Trace
v0.1.0 records — one per change event by default, wrapped in a self-describing
bundle ({agent_trace_version, producer, note, records: [...]}). Two agent-trace-only
flags: --ndjson streams one record per line for large histories, and
--collapse-by-session merges events sharing a session_id into a single record.
Selvedge’s reasoning and entity-level provenance ride along in each record’s
metadata under the reverse-domain dev.selvedge namespace. See the
Agent Trace interop page for the full mapping.
selvedge backfill-commit --hash HASH [--window MIN]
Section titled “selvedge backfill-commit --hash HASH [--window MIN]”Manually backfill git_commit on recent events within a configurable time window.
Called by the post-commit hook automatically; you only run this manually if the hook
isn’t installed and you want to associate a recent commit with already-logged events.
Maintenance
Section titled “Maintenance”selvedge backup [--output FILE] [--json]
Section titled “selvedge backup [--output FILE] [--json]”Snapshots the store with SQLite VACUUM INTO. Defaults to
.selvedge/backups/selvedge-YYYYMMDD-HHMMSS.db, keeping the most recent 7 snapshots and
pruning older ones (custom --output destinations outside that directory are never
pruned). The backups directory is kept out of git — selvedge init (v0.3.5+) appends it
to the project .gitignore, and the first selvedge backup run backfills that entry on
older repos.
selvedge prune [--days N] [--json]
Section titled “selvedge prune [--days N] [--json]”Trims old tool_calls telemetry rows only — it never deletes change events. Default
retention is 90 days; pass --days N to override. Every run appends a one-liner to
.selvedge/prune.log so the cadence shows up in selvedge doctor.
There is no --include-events flag yet — the destructive events-prune path lands in
v0.3.10 alongside .selvedge/config.toml, and will require both SELVEDGE_DESTRUCTIVE=1
and an interactive confirmation.
selvedge prune # trim tool_calls older than 90 daysselvedge prune --days 30selvedge prune --jsonTime strings
Section titled “Time strings”--since and other time-flavored flags accept:
| Form | Meaning |
|---|---|
15m | Last 15 minutes (m = minutes) |
24h | Last 24 hours |
7d | Last 7 days |
5mo or 5mon | Last 5 months (mo / mon = months) |
1y | Last year |
2026-04-22T10:00:00Z | ISO 8601 timestamp (any tz, normalized to UTC) |
Unparseable inputs (e.g. --since yesterday) exit with a clear error rather than
silently returning empty results.
m means minutes, not months. This was a v0.3.0 fix — earlier versions used m
for months, which contradicted every CLI convention (sleep 5m, kubectl --since=5m,
Prometheus). If you’re on v0.2.x, 5m will read as five months — upgrade.
Environment variables
Section titled “Environment variables”| Variable | Purpose |
|---|---|
SELVEDGE_DB | Force a specific DB path (per-session override) |
SELVEDGE_LOG_LEVEL | DEBUG / INFO / WARNING / ERROR (default WARNING) |
SELVEDGE_QUIET=1 | Suppress the global-fallback stderr warning |
Configuration page → for full details on DB resolution and project / global precedence.