Nekyia
The rite for questioning the dead, pointed at the session you lost.
Nekyia (Νέκυια) is the rite in Book XI of the Odyssey. Odysseus digs a pit at the edge of the world and the dead rise to be questioned, and he is not there to mourn them: Tiresias knows the way home and he does not.
- TypeScript
- Bun
- SQLite
- Ink
GitHub (opens in a new tab)README (opens in a new tab)Changelog (opens in a new tab)
What it does
The context you need is usually in a session you already had. You worked the problem out three weeks ago, in a different directory, possibly in a different client, and the only way back to it is to remember enough of it to search for it. So you describe it to a fresh agent instead and pay for the reasoning twice.
Nekyia searches the transcript stores your agent CLIs already keep on disk, ranks what comes back, and launches the client. Where the exact resume command was tested, it attaches to that session by ID. Where it was not, it starts a fresh session with a handover built from the indexed prompts, the touched files and the branch, and says plainly that it is a brief rather than a recovered state.
That distinction is the whole design. A tool that claims to resume everything and quietly starts something new is worse than one that does less and tells you which it did.
Quick start
Nekyia needs Bun 1.1 or newer. It is pre-release and not on npm yet, so it installs from the repository. Both names work: nekyia and the shorter nek.
bun install -g github:AraneaDev/Nekyia
nekyia indexThe first run shows what it intends to read and waits for consent before it opens a transcript store or creates an index. --yes skips that prompt once you have looked at the boundary.
The picker
The picker opens on the project you are standing in. Start it from your home directory, from a filesystem root, or from somewhere nothing has been indexed under, and it opens on the whole index instead, because a list scoped to that directory would be empty.
Typing filters as you go and the matching span is lit in every title, so the list answers each keystroke instead of only getting shorter.
tab widens to every directory, and pressing it again narrows to the project of the row you are on, so you can start anywhere and end up somewhere specific. The count beside the search line always names what is being searched, and where that is one project, it is named next to the count.
A query that matches nothing says what to try rather than leaving you on an empty screen.
ctrl+f cycles the clients your index actually holds, so you do not page past empty filters to reach the one you use. ctrl+p and ctrl+y copy the opening prompt and the command that would run, for when you want either of them somewhere else.
Reading a session before you resume it
ctrl+o opens the session under the cursor and gives it the screen: what you asked and what came back, in the order it was said, and which files moved. A long reply wraps rather than running off the right edge. The arrow keys scroll a line, the page keys scroll a screen, and esc closes it again.
The picker lays itself out against the terminal it is drawn in, so a narrow window gets the same interface at a smaller size rather than a broken one.
From the command line
Run for real on this machine, abridged with '…'.
What it found:
$ nekyia doctor
clients
agy 99 sessions (built-in)
claude 105 sessions (built-in)
codebuff 56 sessions (built-in) [partial]
codex 6 sessions (built-in)
copilot 0 sessions (built-in)
kilo 1 sessions (built-in)
opencode 2 sessions (built-in)
index
267 sessions, 16 size-capped, 0 partly unreadable, 6 missing from disk
size-capped: codebuff:18843754-fafe-4461-bf1a-6b9b878dc4a8
…Seven clients, one index. Four of them resume by ID; the other three get a briefed session, and doctor is where you find out which is which before it matters. A session that ran into the size cap is counted apart from one it could not read, because raising the cap and re-indexing recovers the first and does nothing for the second.
Searching without the picker:
$ nekyia search reconnect race
$ nekyia search reconnect --json # machine-readable, with the transcript paths
$ nekyia blame src/sse.ts # sessions that touched this exact file
$ nekyia timeline --dir . # every file operation recorded under a directory
$ nekyia last # newest session under this directory
$ nekyia show <uid> # the handover, as Markdown, before you send itSearch is scoped to the current directory by default. --all widens it, --client <id> narrows to one client, and --file <path> finds the sessions that touched a file. blame reverses that default: it resolves the path from where you are standing and then searches everywhere, newest first. Touched means the path appeared in indexed tool input, not that the session changed the file. With --json, every row carries the transcript paths, so an agent can read the original instead of trusting the indexed summary.
What happened to your files
blame answers for one file. timeline answers for a directory: every file operation recorded under it, grouped by the session that did it.
$ nekyia timeline --dir . --since 7d --limit 2
/home/dev/work/api-gateway · 2 sessions · 12 events · git was not consulted
exact order inside a session, end-time order between them
* claude 23m api-gateway the retry budget is shared across tenants, it should be per tenant
2 read src/gateway/retry-budget.ts
3 edit src/gateway/retry-budget.ts
8 read src/gateway/tenant.ts
9 edit src/gateway/tenant.ts
14 read test/retry-budget.test.ts
15 write test/retry-budget.test.ts
o codex 6h api-gateway add structured logging around the upstream timeout path
2 read src/gateway/logging.ts
3 edit src/gateway/logging.tsThe number in front of an operation is the turn it happened on, so every line points back into the session's own history.
Inside a session the order is exact. Between sessions the index only knows end times, so the operations stay grouped per session rather than merged into one stream that would claim more precision than there is. Where the directory is a git repository, a path git does not track is marked untracked, and where git could not be asked at all the header says so outright, because a missing marker would otherwise read as "git tracks this". Recovering what a session did means reading both: tracked only means git knows the path, not that it holds the latest edits. A session that ran from somewhere else and named these files by relative path is not found here, the same limit blame has.
One thing to know before pointing it at an older index. File operations are recorded from the next time a session is read in, so sessions indexed before this existed list their files with no operations against them, and a plain nekyia index does not fill them in: it only re-reads sessions whose transcript changed, and an old transcript has not. nekyia index --rebuild does. The output names the sessions in that state instead of showing them as though nothing happened.
How it indexes
Indexing runs in two phases. Discovery reads bounded metadata and a stable fingerprint per session; hydration runs only for what changed, and commits metadata and search facets to SQLite atomically. Search is FTS5, weighting titles, your prompts and selected assistant prose differently, then blending relevance against a recency half-life. Fork chains collapse to one row.
Tool output is not indexed. Command results and file dumps are large, noisy, and the most likely place for something private to be sitting, and none of that is what you search a session by.
Configuration
The index lives at ~/.local/share/nekyia/index.db and the config at ~/.config/nekyia/config.json, both honouring XDG_DATA_HOME and XDG_CONFIG_HOME.
There is no network service, no API key and no telemetry, and the handover is deterministic, so building one makes no model call. What the index does hold is a copy of text that was already on your disk, and that copy outlives the transcript it came from. Three commands control that:
nekyia forget <uid> # one session, and every facet of it
nekyia prune --missing # sessions whose source files are gone
nekyia exclude '/work/private/**' # then: nekyia index --rebuildIt does not promise secret redaction or an encrypted index, so read what show, doctor and --json print before you paste any of it somewhere public.
A client it does not know yet can be described locally: user manifests live in ~/.config/nekyia/clients/*.json, and nekyia doctor --sniff inspects likely stores and scaffolds a draft rather than guessing at a path.