Status, intent, and lineage for Claude Code and Cursor plan files.
Claude Code and Cursor leave plan files behind. After a few hundred of them you cannot tell which finished, which you still care about, or which plan replaced which — the filenames are random and the files say nothing about their own state. pentimento derives that state and gives you a CLI to list, filter, and render the lot as a lineage tree.
Three kinds of plan are worth finding again:
- The long one: an infrastructure migration designed over months grows
subplans, absorbs decisions made in discussion, and leaves behind the
branches you rejected — the part you want back a quarter later. A
superseded plan is a decision record, not garbage, which is why
supersededis the one status no derivation produces or overwrites;tree <id>brings the whole thread back, tags or no tags. - The finished one that is not over: execution ends with findings you will
not act on today. Tag it and set an intent, and
list --tagorlist --starredbrings it back when you are ready to pick the thread up again. - The one that already answered your question: a plan from another project
holds the reasoning behind a decision your current change would undo — why
a CI matrix was cut, why one service avoids a library. A memory exists only
if an agent chose to write one, and project docs only if you did; a plan
exists whenever a decision was planned.
list --titleandlist --grepsearch every project's plans at once, and theprior-plansskill has the agent run that search itself before it proposes a change.
A pentimento is the earlier composition showing through a repainted canvas; that is what a plans directory is.
Built with Claude Code.
pip install pentimento
# or from source:
pip install git+https://github.com/kjiwa/pentimento.gitTab completion for bash, zsh, and fish is in
docs/reference.md#shell-completion.
Point AGENT_PLANS_DIR at your plans directory (it defaults to
~/.claude/plans), then:
pentimento list # see the corpus; derived fields show without backfill
pentimento backfill # persist derived fields so they outlive the transcripts
pentimento set some-plan-id --intent active
pentimento list --starredTo park a finished plan you mean to return to, tag it and set an intent, then find it by tag later:
pentimento set some-plan-id --add-tag auth --intent someday
pentimento list --tag authTo pull one thread of subplans back out by lineage, rather than by tag:
pentimento tree some-plan-id
pentimento tree some-plan-id --ancestorsTo find how an earlier decision was made, search titles (or titles and bodies) across every project, then reopen the plan; to see what you finished recently, filter by date:
pentimento list --title 'github actions|\bGHA\b'
pentimento list --grep 'concurrency group' --status complete
pentimento show some-plan-id --full
pentimento list --status complete --since 1wdocs/workflows.md walks each of these end to end.
Sources and their default directories are covered in docs/integrations.md; Cursor's rules and caveats are in docs/integrations.md.
The samples below are regenerated by sh demo/capture.sh.
PLAN shows the short
id,
such as auth-rollout for api-auth-rollout. --columns (or
PENTIMENTO_COLUMNS) chooses which columns show and in what order; see
Columns.
list and tree share their filters, listed in the
synopsis.
PLAN STATUS INTENT PROJECT SOURCE TITLE TAGS CREATED UPDATED
style-guide superseded abandoned platform claude Write a docs style guide 2026-07-31 6w
auth-redesign complete abandoned platform claude Redesign the auth API [auth, +1] 2026-08-05 5w
dunning-copy complete someday billing claude Rewrite dunning email copy [billing] 2026-08-20 3w
auth-rollout partial active platform claude Roll out the new auth API [auth, +1] 2026-08-25 2w
auth-cleanup not-started queued platform claude Remove the old auth API [auth, +1] 2026-08-30 2w
auth-docs not-started unset platform claude Document the new auth API 2026-09-02 1w
invoice-retry unknown unset billing claude Retry failed invoice charges [billing] 2026-09-04 1w
relevance-tuning not-started active billing claude Tune search relevance [search] 2026-09-09 5d
onboarding-checklist not-started unset claude Write the onboarding checklist 2026-09-13 1d
9 plans
Below the table threshold, list stacks each plan into a record; see
the layout rule.
Write a docs style guide
style-guide superseded abandoned platform claude 2026-07-31 6w
Redesign the auth API
auth-redesign complete abandoned platform claude [auth, security]
2026-08-05 5w
Rewrite dunning email copy
dunning-copy complete someday billing claude [billing] 2026-08-20 3w
Roll out the new auth API
auth-rollout partial active platform claude [auth, security] 2026-08-25
2w
Remove the old auth API
auth-cleanup not-started queued platform claude [auth, security]
2026-08-30 2w
Document the new auth API
auth-docs not-started unset platform claude 2026-09-02 1w
Retry failed invoice charges
invoice-retry unknown unset billing claude [billing] 2026-09-04 1w
Tune search relevance
relevance-tuning not-started active billing claude [search] 2026-09-09
5d
Write the onboarding checklist
onboarding-checklist not-started unset claude 2026-09-13 1d
9 plans
Plans nested under their parents, grouped by project. Plain tree renders
the whole corpus this way; tree <id> roots it at one plan instead — that
plan plus everything beneath it (see
tree <id>).
--ancestors also walks up to <id>'s topmost
ancestor, spine only, for pulling a single thread out of a larger forest.
(no project)
`-- Write the onboarding checklist
onboarding-checklist not-started unset 2026-09-13 1d
billing
|-- Rewrite dunning email copy
| dunning-copy complete someday [billing] 2026-08-20 3w
|-- Retry failed invoice charges
| invoice-retry unknown unset [billing] 2026-09-04 1w (parent elided: no-such-plan)
`-- Tune search relevance
relevance-tuning not-started active [search] 2026-09-09 5d
platform
|-- Write a docs style guide
| style-guide superseded abandoned 2026-07-31 6w
`-- Redesign the auth API
auth-redesign complete abandoned [auth, security] 2026-08-05 5w
`-- Roll out the new auth API
auth-rollout partial active [auth, security] 2026-08-25 2w
|-- Remove the old auth API
| auth-cleanup not-started queued [auth, security] 2026-08-30 2w
`-- Document the new auth API
auth-docs not-started unset 2026-09-02 1w
9 plans
platform
`-- Redesign the auth API
auth-redesign complete abandoned [auth, security] 2026-08-05 5w
`-- Roll out the new auth API
auth-rollout partial active [auth, security] 2026-08-25 2w
|-- Remove the old auth API
| auth-cleanup not-started queued [auth, security] 2026-08-30 2w
`-- Document the new auth API
auth-docs not-started unset 2026-09-02 1w
4 of 9 plans
# Roll out the new auth API
id: api-auth-rollout
path: ~/.claude/plans/api-auth-rollout.md
status: partial intent: active tags: [auth, security]
parent: api-auth-redesign project: platform
created: 2026-08-25 source: claude modified: 2026-08-25 12:30
Progress
[x] Ship behind a feature flag
[ ] Flip the flag for all tenants
Context
Tenants opt in via the auth_v2 flag in tenant_settings. Watch error rates before flipping the
remaining cohort. See the rollout runbook.
Cohort Status
internal complete
beta in progress
check validates the whole corpus and exits 1 on any finding; it takes no
plan id. PLAN uses the short id, and a line under the summary gives the fix
for each CODE. --format json|tsv emits the full id in id and the fix in
hint. To work through findings, see
Working through check;
docs/troubleshooting.md
explains each CODE.
CODE PLAN MESSAGE
dangling-parent invoice-retry parent 'no-such-plan' does not resolve to a plan
underivable-status invoice-retry '## Progress' has no checkboxes or recognized phrase
status-behind-history auth-cleanup status 'not-started' but 1 later session worked this plan
unadopted-tag auth-docs no tags, but its thread carries [auth, security]
9 plans checked, 4 findings
dangling-parent: pentimento set <id> --parent <id>, or --clear-parent
status-behind-history: tick the plan's '## Progress', or pentimento history <id>, then pentimento set <id>
--status <value> (pins)
unadopted-tag: pentimento set <id> --add-tag <tag>
underivable-status: add a checklist to '## Progress', or pentimento show <id>, then pentimento set <id>
--status <value>
narrow with: pentimento list --finding <code>
history shows which sessions touched a plan's file. The session whose id
matches the plan's own id, or failing that the session whose first touch
wrote the plan, is authored; any later session that edited, wrote, or
delegated work on it is worked; one that only read it is read. Only Claude
Code transcripts feed history.
For an empty result, see
history is empty.
WHEN WHAT SESSION TOUCHES
2026-08-30 12:30 authored auth-cleanup 1
2026-09-11 12:30 worked implement-api-auth-cleanup-eager-wolf 1
2026-09-13 12:30 read review-api-auth-cleanup-calm-fox 1
---
pentimento:
status: not-started | partial | complete | superseded | unknown
pinned: true # omitted unless set
intent: active | queued | someday | abandoned | unset
tags: [auth, security] # omitted if untagged
parent: some-other-plan-id # omitted for roots
project: platform # omitted if undetermined
created: 2026-09-08
---The vocabulary lives in one place: pentimento/vocabulary.py.
| Field | Set by | How |
|---|---|---|
status |
derived | Views derive it live from status signals, first match wins; backfill (including the per-write pentimento hook, which caps it at partial) persists it: ## Progress, then a Cursor plan's todos:, then checkboxes elsewhere in the body. set --status overrides it directly and pins it (see pinned); it is the only way to set superseded, which no derivation produces or overwrites. |
pinned |
operator | Never derived. set --status sets it to true automatically; set --unpin clears it. While set, backfill (with or without --rederive) leaves status untouched; see check findings for what check still reports. |
intent |
operator | Shown as unset until set; backfill writes unset the first time it sees the plan, then leaves it alone. Only set --intent changes it after that. |
tags |
operator | Never derived or written; check suggests them (unadopted-tag). set --add-tag/--remove-tag/--clear-tags; filter with list/tree --tag, which ANDs repeated tags. |
parent |
derived, or operator | Views derive it from a plan reference and backfill persists it (see parent is empty). --rederive recomputes it from scratch: it replaces a parent set with set --parent by the derived one, or removes it when no reference resolves. set --parent/--clear-parent set or clear it directly; set --parent rejects a value that would create a cycle. Read the chain back with tree <id>/tree <id> --ancestors. |
project |
derived, or operator | Views derive it from a session's cwd and backfill persists it, which keeps it after Claude Code prunes the transcript (a Cursor plan's: see Cursor). set --project/--clear-project set or clear it directly; --project . resolves to the current directory's name. |
created |
derived once | A local date, derived by views and persisted once by backfill, then immutable except through backfill --recreate. |
modified |
derived, not stored | Not a frontmatter field: max(session end time, file mtime). Neither backfill nor set bumps it when the write only touches frontmatter bookkeeping. |
Lineage and source discovery are covered in full in
docs/integrations.md
and
docs/troubleshooting.md.
Cursor plans get project and prompt lineage from Cursor's agent transcripts,
matched by name; a stop hook keeps their status current. The
matching rule
is in the integrations guide.
| Command | Does |
|---|---|
list |
flat table of plans |
tree [<id>] |
lineage tree, grouped by project |
show <id> |
H1, frontmatter, and the rendered body |
set <id>... |
rewrite frontmatter in place |
backfill |
gap-fill intent/created/project/parent; advance status |
hook |
run as a Claude Code PostToolUse hook; reads the payload on stdin |
index |
write INDEX.md into the plans directory |
check |
validate lineage, vocabulary, status, and tags; exits 1 on any finding |
history <id> |
session-touch history for a plan |
completion <shell> |
print a shell integration script |
Full flags for every command, plus the environment variables, are in docs/reference.md.
pentimento is built for one operator's corpus on one machine. Shared,
concurrent, or multi-author planning is out of scope and not a gap this tool
intends to close — project, prompt lineage, and modified are all
derived from local Claude Code transcripts, and deriving them across authors
would need a different source, a sync, and an identity model.
Keeping the plans directory in git does get you review and history, and part
of the derived state travels with the files: status, operator-set
frontmatter, and body-referenced parent survive a checkout anywhere;
project, prompt-derived parent, and session history do not. See
docs/workflows.md
for the details, and pentimento index for an INDEX.md worth committing.
ccplan and
planc track Claude Code plans by a status
you set by hand, ccplan in a sidecar file and planc in frontmatter through a
TUI. claude-plan-viewer
browses and searches them in a web UI.
planning-with-files keeps
an agent's plan on disk while it works and recovers it after /clear or
compaction; it manages the files it creates, not a directory of finished
ones. None of them records which plan replaced which. pentimento reads a
corpus it did not author and derives status, project, and parent across it.
The longer comparison is in
Managing Claude Code plan files.
Stdlib-only Python 3.9+, zero runtime dependencies, no PyYAML.
pentimento enriches modified and lineage by reading Claude Code's session
transcripts (AGENT_SESSIONS_DIR, default ~/.claude/projects) and Cursor's
agent transcripts (CURSOR_SESSIONS_DIR, default ~/.cursor/projects), both
undocumented, private formats. If a format changes, or the transcripts are
absent, this enrichment degrades to file mtimes and plain body/preamble
references — it does not break, and the frontmatter itself stays plain,
hand-editable markdown either way.
Setup, checks, and CI are in CONTRIBUTING.md.
- docs/reference.md — every command's full flags, and the environment variables.
- docs/integrations.md
— wiring
backfillandpentimento hookinto Claude Code and Cursor, a slash command, a skill that searches past plans before a new one, a triage-nudge pattern,checkin CI. - docs/workflows.md
— triage, picking a plan back up, reusing a past decision, supersession,
lineage trees, working through
check, scripting with--format json. - docs/troubleshooting.md
— every empty field and
checkfinding, explained.

0 comments
log in to comment.