Log a code change
log_changeRecord structured change events for codebase entities with diffs, reasoning, and support for renames and supersedes to build queryable history.
Instructions
Record a change to a codebase entity.
Call this immediately after making any meaningful change. The event is
written to the local SQLite store and returned with its assigned id and
timestamp. If the reasoning fails the quality validator (empty, too
short, or a generic placeholder), or the entity_path doesn't match the
usual shape for its entity_type, the result includes a warnings
array — the event is still stored.
Renames: pass the new path in entity_path, set change_type="rename",
and pass the old path in rename_from. Selvedge then writes two events —
a rename on the old path and a create on the new path with
metadata.renamed_from set — so the entity's history follows it. Example:
log_change(
entity_path="src/auth/session.py::login", # new path
change_type="rename",
rename_from="src/auth.py::login", # old path
entity_type="function",
reasoning="Split auth.py into an auth/ package; login moved.",
)Superseding a reverted decision: when a reverted change becomes correct
again (the constraint that killed it no longer holds), do NOT delete or
edit history — log with change_type="supersede" and the reason. The
new event links the prior revert (auto-resolved when supersedes is
empty) and every read surface then reports the trail
tried → reverted → re-opened. Never re-apply a reverted change without
superseding it first.
On validation failure (invalid change_type, missing entity_path,
rename_from set without change_type='rename', supersedes set without
change_type='supersede', or a supersede with nothing to re-open) the
result is {"status": "error", "error": "..."} with no event written.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| diff | No | The actual change — SQL migration text, code diff, or a human-readable description of what changed. Optional but strongly recommended for non-trivial changes. | |
| agent | No | Name/ID of the AI agent making the change (e.g. 'claude-code', 'cursor', 'copilot', 'human'). | |
| project | No | Repository or project name. Useful when one DB tracks multiple projects. | |
| reasoning | No | Why the change was made. Include the user's original request, the problem being solved, or any context that won't be obvious from the diff alone. Good example: 'User asked to add 2FA — needs phone number to send SMS verification codes.' Avoid generic placeholders like 'user request' or 'done' — these are flagged by the quality validator and returned in `warnings`. | |
| constraint | No | Optional: the testable principle behind the decision, kept queryable (e.g. 'card data in our own DB = PCI scope'). | |
| git_commit | No | The git commit hash this change will land in. Can be backfilled later via `selvedge backfill-commit` or the post-commit hook. | |
| session_id | No | The agent session or conversation ID, if available. | |
| stale_when | No | Optional: what would invalidate this decision (e.g. 'payment provider changed'). stale_decisions matches it against later events and flags 'review suggested' — surfacing only. | |
| supersedes | No | Id of the prior event this change overrides; only valid with change_type='supersede'. Empty auto-links the entity's most recent remove/delete. Append-only — the old verdict is never edited, just derived as superseded. | |
| change_type | Yes | What kind of change. One of: add, remove, modify, rename, retype, create, delete, index_add, index_remove, migrate, revert (tried and rolled back), supersede (re-open a reverted decision). Invalid values are rejected — pick the closest match. | |
| entity_path | Yes | Dot/slash-notation path to the entity. Required and non-empty. Examples: 'users.email' (DB column), 'users' (DB table), 'src/auth.py::login' (function in file), 'src/auth.py' (file), 'api/v1/users' (API route), 'deps/stripe' (dependency), 'env/STRIPE_SECRET_KEY' (env variable). | |
| entity_type | No | Category of entity. One of: column, table, file, function, class, endpoint, dependency, env_var, index, schema, config, other. Unknown values are coerced to 'other'. | other |
| rename_from | No | The entity's previous path, when this change is a rename. Set it together with change_type='rename' and put the NEW path in entity_path. Selvedge records the dual-event rename pattern: a 'rename' event on the old path and a 'create' event on the new path whose metadata.renamed_from points back to the old one, so blame/diff/prior_attempts on the new path still see the history. Leave empty for any non-rename change. | |
| changeset_id | No | Optional grouping ID for related changes that belong to the same feature or task. Use a short slug like 'add-stripe-billing'. All events sharing a changeset_id can be queried together via the `changeset` tool. | |
| revisit_after | No | Optional revisit date for an architectural decision (table, schema, dependency, config). An ISO date OR a relative offset from this event's timestamp (e.g. '90d', '6mo'). `stale_decisions` surfaces it once it passes, if the entity is still in active use. Leave empty otherwise. |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | ||
| error | Yes | ||
| status | Yes | ||
| warnings | Yes | ||
| timestamp | Yes | ||
| supersedes | Yes |