Clean Up Local Event Logs
Every spec-kitty next run writes a run journal under .kittify/runtime/runs/, and the glossary keeps one event log per Mission under .kittify/events/glossary/. These files are local: git ignores them, and nothing removes them on its own, so .kittify/ keeps growing. Use spec-kitty doctor event-logs to see what is past retention and remove it.
Preview what would be removed
Run the command without options. It lists every item it looked at and changes nothing:
spec-kitty doctor event-logs
The report has two lists:
- Candidates: the items
--applywould delete, each with its path, age and reason. - Kept: everything else, grouped by the reason it stays.
Each item names its surface: the kind of state file it is, by its name in the Spec Kitty state registry (for example runtime_run_event_log for a run directory or glossary_fallback_events for a glossary log).
For a script, add --json:
spec-kitty doctor event-logs --json
The payload holds:
applied:trueafter--apply,falsefor a preview.limits:keep_runs,max_age_daysandsource, which is.kittify/config.yamlwhen the limits come from that file anddefaultotherwise.candidates,kept,deleted: lists of items. Every item carriessurface,kind(run,mission_logorcache),path(relative to the project),mission(the Mission directory name underkitty-specs/, ornullwhen there is none),age_daysandreason.failed: the items whose deletion failed, each with the item fields pluserror, the error text.removed_index_entries: the run-index entries removed with their runs.
When the command stops with exit code 2, --json prints an error envelope instead: {"ok": false, "error": {"code": ..., "message": ...}}. The codes are config_error (the configuration cannot be read or is invalid), not_in_project (not run inside a Spec Kitty project) and retention_policy_drift (an internal error, see below).
Read the reasons
| Reason | Meaning |
|---|---|
past retention; Mission completed |
A candidate: outside the newest keep_runs, older than max_age_days, and its work is over (see below). |
rebuildable cache |
A candidate: a derived Mission view under .kittify/derived/. It is rebuildable: Spec Kitty rebuilds it the next time it is read. |
within keep_runs |
Kept: one of the newest keep_runs items of its kind. |
younger than max_age_days |
Kept: modified within the last max_age_days days. |
Mission is open |
Kept: its work is not over yet (see below). |
Mission not found |
Kept: this checkout has no Mission with that identity, for example because it lives on another branch. |
lock held |
Kept: another process is using it right now. |
An item is removed only when it is past BOTH limits and its work is over:
- A run is over when its Mission is merged, or when the run itself finished (its journal records that the run completed). A run of a Mission whose work packages are all done but which was never merged stays until the Mission is merged or the run finishes.
- A glossary log is over when its Mission is completed: merged, or every work package done or canceled.
A run's Mission is the one spec-kitty next recorded for it in the run index. Rebuildable caches are candidates whatever their age, unless locked.
Tune the limits
The limits live under ledger.retention in .kittify/config.yaml. Without that block the defaults apply (keep_runs: 20, max_age_days: 30):
ledger:
retention:
keep_runs: 50 # protect the newest 50 items of each kind
max_age_days: 90 # and everything modified in the last 90 days
Both values must be whole numbers of 0 or more. An invalid value, an unknown key, a .kittify/config.yaml that is not valid YAML, or a ledger or ledger.retention that is not a mapping makes the command stop with exit code 2 and a message naming the problem; nothing is scanned or deleted.
Remove the candidates
When the preview looks right, delete exactly the listed candidates:
spec-kitty doctor event-logs --apply
Each candidate's lock is checked again just before it is deleted, so an item that became busy is kept and reported as lock held. When a run directory is deleted, its entry in .kittify/runtime/feature-runs.json goes with it, and the report lists it under the removed run-index entries.
The exit code tells you how it went:
| Exit code | When |
|---|---|
0 |
A preview, or an apply where every deletion succeeded (or there was nothing to delete). |
1 |
An apply where at least one deletion failed. The failed list names each item and its error. |
2 |
Not inside a project (not_in_project); the configuration cannot be read or ledger.retention is invalid (config_error); or an internal error where the state registry and the cleanup engine disagree (retention_policy_drift). Nothing was scanned or deleted. Please report a retention_policy_drift error. |
What is never removed
- Committed Mission records:
status.events.jsonlanddecisions.events.jsonl. - The Op records under
kitty-ops/and the Op index,kitty-ops/ops-index.jsonl.spec-kitty invocations listreads the index as it is, so removing it would hide Op history. - The run index file,
.kittify/runtime/feature-runs.json. Only the entries of deleted runs leave it. - Lock files.
- The glossary logs that belong to no Mission (
_cli,_renderer). - The logs and runs whose work is not over, or whose Mission this checkout cannot find.
- Anything whose lock another process holds.