# Show HN: Pentimento – status and lineage for your coding agent's plan files

> Source: <https://github.com/kjiwa/pentimento>
> Published: 2026-11-10 13:44:19+00:00

Status, intent, and lineage for Claude Code, Cursor, and Antigravity plan files.

Claude Code, Cursor, and Antigravity 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
`superseded` is 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 --tag` or`list --starred` brings 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 --title` and`list --grep` search every project's plans at once, and the[`prior-plans` skill](https://github.com/kjiwa/pentimento/blob/main/docs/integrations.md#prior-plans-skill) has the agent run that search itself before it proposes a change.

In harness-engineering terms, plans are the state layer: what one session
leaves for the next. `pentimento hook` keeps that state current as the agent
writes it, and the `prior-plans` skill has the agent read it back.

A pentimento is the earlier composition showing through a repainted canvas; that is what a plans directory is.

Built with [Claude Code](https://claude.com/claude-code).

```
pip install pentimento
# or from source:
pip install git+https://github.com/kjiwa/pentimento.git
```

Tab completion for `bash`, `zsh`, and `fish` is in
[docs/reference.md#shell-completion](https://github.com/kjiwa/pentimento/blob/main/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 --starred
```

To 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 auth
```

To pull one thread of subplans back out by lineage, rather than by tag:

```
pentimento tree some-plan-id
pentimento tree some-plan-id --ancestors
```

To 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 1w
```

[docs/workflows.md](https://github.com/kjiwa/pentimento/blob/main/docs/workflows.md)
walks each of these end to end.

Sources and their default directories are covered in
[docs/integrations.md](https://github.com/kjiwa/pentimento/blob/main/docs/integrations.md);
Cursor's and Antigravity's rules and caveats are in the
[Cursor](https://github.com/kjiwa/pentimento/blob/main/docs/integrations.md#cursor) and
[Antigravity](https://github.com/kjiwa/pentimento/blob/main/docs/integrations.md#antigravity) sections.

The samples below are regenerated by `sh demo/capture.sh`.

`PLAN` shows the [short
id](https://github.com/kjiwa/pentimento/blob/main/docs/reference.md#plan-ids),
such as `auth-rollout` for `api-auth-rollout`. `--columns` (or
`PENTIMENTO_COLUMNS`) chooses which columns show and in what order; see
[Columns](https://github.com/kjiwa/pentimento/blob/main/docs/reference.md#columns).
`list` and `tree` share their filters, listed in the
[synopsis](https://github.com/kjiwa/pentimento/blob/main/docs/reference.md#commands).

```
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](https://github.com/kjiwa/pentimento/blob/main/docs/reference.md#columns).

```
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>`](https://github.com/kjiwa/pentimento/blob/main/docs/reference.md#flags)).
`--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`](https://github.com/kjiwa/pentimento/blob/main/docs/workflows.md#working-through-check);
[docs/troubleshooting.md](https://github.com/kjiwa/pentimento/blob/main/docs/troubleshooting.md#check-findings)
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](https://github.com/kjiwa/pentimento/blob/main/docs/troubleshooting.md#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](https://github.com/kjiwa/pentimento/blob/main/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`](https://github.com/kjiwa/pentimento/blob/main/docs/reference.md#flags) ) 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](https://github.com/kjiwa/pentimento/blob/main/docs/troubleshooting.md#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](https://github.com/kjiwa/pentimento/blob/main/docs/troubleshooting.md#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 or Antigravity plan's: see[Cursor](https://github.com/kjiwa/pentimento/blob/main/docs/integrations.md#cursor) and[Antigravity](https://github.com/kjiwa/pentimento/blob/main/docs/integrations.md#antigravity) ).`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](https://github.com/kjiwa/pentimento/blob/main/docs/integrations.md)
and
[docs/troubleshooting.md](https://github.com/kjiwa/pentimento/blob/main/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](https://github.com/kjiwa/pentimento/blob/main/docs/integrations.md#cursor)
is in the integrations guide.
Antigravity plans read their own conversation's transcript, so they need no
matching, and a `PostToolUse` hook keeps their status current
([setup](https://github.com/kjiwa/pentimento/blob/main/docs/integrations.md#antigravity)).

| 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 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](https://github.com/kjiwa/pentimento/blob/main/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](https://github.com/kjiwa/pentimento/blob/main/docs/workflows.md)
for the details, and `pentimento index` for an `INDEX.md` worth committing.

[ccplan](https://github.com/sorafujitani/ccplan) and
[planc](https://github.com/jakebf/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](https://github.com/HelgeSverre/claude-plan-viewer)
browses and searches them in a web UI.
[planning-with-files](https://github.com/OthmanAdi/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](https://dev.to/kjiwa/managing-claude-code-plan-files-lineage-status-and-existing-tools-37b6).

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`), and
Antigravity's conversation transcripts (next to each plan under
`ANTIGRAVITY_BRAIN_DIR`, default `~/.gemini/antigravity/brain`), all
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](https://github.com/kjiwa/pentimento/blob/main/CONTRIBUTING.md).

- [docs/reference.md](https://github.com/kjiwa/pentimento/blob/main/docs/reference.md) — every command's full flags, and the environment variables.
- [docs/integrations.md](https://github.com/kjiwa/pentimento/blob/main/docs/integrations.md) — wiring`backfill` and`pentimento hook` into Claude Code, Cursor, and Antigravity, a
slash command, a skill that searches past plans before a new one, a
triage-nudge pattern,`check` in CI.
- [docs/workflows.md](https://github.com/kjiwa/pentimento/blob/main/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](https://github.com/kjiwa/pentimento/blob/main/docs/troubleshooting.md) — every empty field and`check` finding, explained.
