Documentation
¶
Overview ¶
Package lifecycle implements USER-DRIVEN session lifecycle operations over Claude Code transcripts: archiving a session's .jsonl out of the active projects tree, and deleting sessions behind a filter gate.
Two safety invariants drive the design (prior-art consensus, all LLM-free):
- Delete is FILTER-GATED and DRY-RUN-FIRST: it refuses to delete every session (>=1 filter must be set), and a dry run reports a plan without touching disk.
- A real delete writes a TOMBSTONE sidecar (a plain text file, one session id per line) so a later index pass can skip a deleted session instead of resurrecting it. The tombstone is NOT a schema change — it is a flat file the indexer consults.
This package is intentionally self-contained: it resolves sessions by walking .jsonl files directly and counts messages by JSONL line count, so it carries no dependency on the index/parse internals. The CLI layer wires the subcommands, flags, and the y/N confirm around these functions.
Index ¶
- Variables
- func Archive(sessionPathOrID, archiveDir string) (string, error)
- func IsTombstoned(cacheDir, sessionID string) (bool, error)
- func LoadTombstones(cacheDir string) (map[string]struct{}, error)
- func MatchesSessionID(stem, id string) bool
- func TombstoneIDs(cacheDir string, ids []string) error
- func TombstonePath(cacheDir string) string
- type DeleteOpts
- type DeletePlan
- type FloorStats
- type PlanItem
Constants ¶
This section is empty.
Variables ¶
var ErrNoFilter = errors.New("refusing to delete all sessions: set at least one filter")
ErrNoFilter is returned by Delete when the caller supplies no filter. Deleting every session must be an explicit, narrowed act — never the default.
Functions ¶
func Archive ¶
Archive moves the session identified by sessionPathOrID into archiveDir, returning the new path. sessionPathOrID may be an absolute/relative path to a .jsonl, or a bare session id resolved against the projects tree (top-level sessions only).
If archiveDir is empty it defaults to ~/.claude/archive/. The move is idempotent: if the source is already inside archiveDir (or the destination already exists and the source is gone), Archive reports success with the archived path rather than erroring.
func IsTombstoned ¶
IsTombstoned reports whether sessionID appears in the tombstone under cacheDir. A missing tombstone means nothing is tombstoned (returns false, nil).
func LoadTombstones ¶
LoadTombstones reads the tombstone at <cacheDir>/.deleted and returns the set of deleted session ids. A missing file is not an error — it yields an empty set. Blank lines and surrounding whitespace are ignored.
func MatchesSessionID ¶ added in v0.5.0
MatchesSessionID reports whether a session id (a .jsonl stem) is addressed by id: exact equality always, prefix only from 8 characters up (the session8 form search output prints). Anything shorter must match exactly — a 3-char prefix silently fanning out to many sessions is how a targeted delete becomes a massacre. Shared by the live walk, the retained scan, and the archive's foreign-session probe so all three answer alike.
func TombstoneIDs ¶ added in v0.3.0
TombstoneIDs appends each id in ids to the tombstone sidecar under cacheDir, wrapping appendTombstones (same atomicity: create-dir, open-append, write). Exported so the CLI can tombstone RETAINED sessions matched by index.RetainedMatches — those have no backing file to os.Remove, so Delete's normal remove-then-tombstone path does not apply; this is the tombstone-only half for that case.
func TombstonePath ¶
TombstonePath returns the path to the tombstone sidecar file: <cacheDir>/.deleted. If cacheDir is empty it defaults to ~/.cache/session-search.
Types ¶
type DeleteOpts ¶
type DeleteOpts struct {
// Before, when non-zero, matches sessions whose transcript file was last
// modified strictly before this instant.
Before time.Time
// Project, when non-empty, matches sessions whose transcript directory path
// contains this substring (case-sensitive).
Project string
// MaxMessages, when > 0, matches sessions with at most this many messages
// (JSONL lines). Use it to prune short/low-signal sessions.
MaxMessages int
// SessionID, when non-empty, matches the one session whose id equals it —
// or starts with it when it is at least 8 characters (the search-output
// session8 form). See MatchesSessionID for the exact rule.
SessionID string
// DryRun, when true, computes and returns the plan WITHOUT deleting anything
// or writing a tombstone.
DryRun bool
}
DeleteOpts carries the filter gate and the dry-run switch for Delete.
At least one of Before / Project / MaxMessages must be set or Delete returns ErrNoFilter. The filters are ANDed: a session must satisfy every set filter to match. A zero-value field is "unset" and does not constrain the match.
type DeletePlan ¶
type DeletePlan struct {
Matched []PlanItem
TotalBytes int64
Deleted bool // false for a dry run
TombstonePath string // where ids were (or would be) appended
}
DeletePlan is the result of a Delete pass — what matched and how much disk it reclaims. For a dry run, Deleted is false and nothing on disk changed; for a real delete, Deleted is true and Matched lists the sessions that were removed and tombstoned.
func Delete ¶
func Delete(projectsRoot, cacheDir string, opts DeleteOpts) (DeletePlan, error)
Delete removes the sessions under projectsRoot that match opts, gated by the filter requirement. projectsRoot is the Claude Code projects root (the dir holding the per-project transcript dirs). cacheDir is where the tombstone sidecar lives (typically ~/.cache/session-search); if empty it defaults to that path.
Behavior:
- No filter set -> ErrNoFilter (never deletes everything).
- opts.DryRun true -> returns the plan, touches nothing on disk.
- Otherwise -> deletes each matched .jsonl and appends its id to the tombstone, then returns the plan with Deleted=true.
type FloorStats ¶ added in v0.10.0
FloorStats are the transcript metrics used by the deterministic routine floor. TotalMessages deliberately counts every parsed record: tool results and hook banners are part of the conservative message-count guard.
func EvaluateMathFloor ¶ added in v0.10.0
func EvaluateMathFloor(messages []model.Message) (bool, FloorStats)
EvaluateMathFloor marks only obviously small sessions as routine. The two conditions are intentionally conjunctive: a single substantive prompt does not pass when the transcript grew large or produced substantial prose.
type PlanItem ¶
type PlanItem struct {
SessionID string // .jsonl stem == the claude --resume id
Path string // absolute path to the .jsonl
Project string // friendly project label (basename of the transcript dir)
Bytes int64 // file size in bytes
Messages int // JSONL line count
}
PlanItem is one session matched by a Delete pass.