Nekyia

agent
Security Audit
Fail
Health Warn
  • License — License: MIT
  • Description — Repository has a description
  • Active repo — Last push 0 days ago
  • Low visibility — Only 5 GitHub stars
Code Fail
  • exec() — Shell command execution in scripts/capture-svg.ts
  • spawnSync — Synchronous process spawning in scripts/capture-svg.ts
  • exec() — Shell command execution in scripts/make-fixtures.ts
  • exec() — Shell command execution in scripts/recovery-census.ts
  • spawnSync — Synchronous process spawning in scripts/recovery-census.ts
Permissions Pass
  • Permissions — No dangerous permissions requested

No AI report is available for this listing yet.

SUMMARY

Search every agent CLI session on your machine and resume the right one

README.md

Nekyia

Find the session. Pick up the thread.

Release
Tool page
CI
License
Language
Last commit
Conventional Commits
Status

The Nekyia picker: a list of sessions from several agent CLIs, and beneath it the selected session's directory, branch, prompts and touched files

Nekyia (Νέκυια) is the rite in the Odyssey through which Odysseus calls up
the dead and asks them what they know. This tool does something less dramatic
with old agent sessions: it brings back the useful context, and an account of
what they did to your files.

Nekyia searches the local histories kept by your agent CLIs, ranks the sessions that
matter, and launches the right client. Verified clients resume the exact session.
Search-tier clients start fresh with a deterministic handover that says plainly it is
a brief, not a resumed state. It can also account for what those sessions did: which
files they touched, in what order, and whether git is currently tracking them.

Status: pre-release. Nekyia is not yet published to npm. Install from the
source repository or from the package attached to the
GitHub pre-release. The command
bun install -g nekyia is the planned published experience and does not work yet.


Features

  • One Search Surface: query Claude Code, Codex, GitHub Copilot CLI, opencode, Kilo Code, Codebuff, and Antigravity histories together
  • Verified Resume: attach to the selected session by ID only where that exact command was tested
  • Deterministic Handovers: start search-tier clients with every indexed user prompt, each message kept whole and in order, touched files, branch context, bounded assistant prose, and a note of whatever had to be left out
  • Two-Phase Indexing: discover cheap fingerprints first, then hydrate only sessions that changed
  • Fast Local Search: SQLite FTS5 combines weighted prompt relevance with recency decay
  • Exact File History: ask which sessions touched one file, resolved against each session's own directory
  • Directory Timelines: see every file operation recorded under a directory, grouped by session, with each path marked against what git already has
  • Interactive and Scriptable: use the virtualized Ink picker or plain, JSON-capable CLI commands
  • Privacy Controls: forget one session, prune deleted sources, or exclude a directory and everything under it
  • Extensible Manifests: describe another client locally and use the conservative sniffer to scaffold a draft
  • Local by Design: no network service, API key, telemetry, model-written summary, or tool-output indexing

Installation

Nekyia requires Bun 1.1 or newer.

From a release

bun install -g github:AraneaDev/Nekyia#v0.0.20

Every published version is listed on the
releases page.

From source

git clone https://github.com/AraneaDev/Nekyia.git
cd Nekyia
bun install --frozen-lockfile
bun link

Both install paths expose nekyia and the shorter nek command.

Quick start

1. Build the local index

nekyia index

The first run shows what Nekyia plans to inspect and asks for consent before it
opens a transcript store or creates the index. Use nekyia index --yes only when
you have already reviewed that boundary and need a non-interactive run.

2. Find a session

nekyia                         # interactive picker
nekyia search reconnect race   # table output
nekyia search reconnect --json # machine-readable output
nekyia blame src/sse.ts        # recent sessions that touched this file
nekyia last                    # newest session under this directory

Search defaults to the current directory. Pass --all to search everywhere,
--client <id> for one client, or --file <path> for sessions that touched a file.
nekyia blame <path> resolves the path from the current directory, then searches
globally and newest-first for that exact normalized file. "Touched" means the path
appeared in indexed tool input; it does not prove that the session modified the file.
--json adds sourcePaths to every row, so an agent can read the raw transcript
itself instead of trusting the indexed summary.

nekyia timeline covers a directory rather than one file. Ordering inside a session is
exact; between sessions it is by end time, which the index knows coarsely, so events stay
grouped by session rather than merged into one stream. A session whose own directory sits
elsewhere and which named these files relatively is not found, the same limit blame has.

$ 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    src/gateway/router.ts
     15  edit    src/gateway/router.ts
     20  read    test/retry-budget.test.ts
     21  write   test/retry-budget.test.ts
     26  read    docs/rate-limits.md
     27  write   docs/rate-limits.md

o  codex        6h  api-gateway       add structured logging around the upstream timeout path
      2  read    src/gateway/logging.ts
      3  edit    src/gateway/logging.ts

The number beside each operation is the turn it happened on, so it points back into the
session's own history. Where the directory is a git repository, each path git does not
track is marked untracked; you should inspect both tracked and untracked
paths when recovering session changes, because tracking only means git knows the path,
not that it has your latest edits. The header says outright when git could not be asked,
as it does above, since a missing marker would otherwise read as "git tracks this".

File operations are recorded from the next hydration onward, so sessions already in the
index list their files without any operations until you run nekyia index --rebuild. A
plain nekyia index will not fill them in: it hydrates only sessions whose transcript
changed, and an old session's transcript has not. Timeline output says which sessions are
in that state rather than showing them as though nothing happened.

The picker opens on the project you are standing in. Started from your home
directory, from a filesystem root, or from somewhere nothing has been indexed under,
it opens on the whole index instead, because a scoped list there would be empty.
tab widens to every directory, and pressing it again narrows to the project of the
row under the cursor, so you can start anywhere and end up in one project. The count
beside the search line always names what is being searched.

Typing filters as you go, and the matching span is lit in every title, so the list
answers each keystroke rather than only shortening.

Searching: the query is lit inside each matching title, and the row under the cursor is marked in the gutter

Narrowing to one project names it, so you always know what is being searched:

The picker narrowed to a single project, named beside the session count

A query that matches nothing says what to try rather than leaving an empty screen:

A search that matched nothing, reading "Nothing came up. Try fewer words."

3. Read the history before you commit to 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. Arrow keys scroll a line, the page keys
scroll a screen, and esc closes it again.

Reading a session's history: the pane fills the screen with the conversation in the order it happened, scrolled past the header

4. Resume or hand over

Press Enter in the picker, or run nekyia last. A resume-tier row launches the
verified exact-session command. A search-tier row asks for confirmation, builds a
deterministic handover, and starts a new client session with that context.

Keys in the picker

Key What it does
type Filter as you go; the match is lit in each title
up / down Move the cursor, or scroll the history while it is open
enter Resume the session, or start a briefed one once you confirm it
ctrl+o Open the session's history, and close it again
ctrl+t Choose another client and confirm a fresh session with this session's context (r for a review framing, n for a custom note)
tab Widen to everywhere, or narrow to the project under the cursor
ctrl+f Cycle the clients your index actually holds
ctrl+p / ctrl+y Copy the opening prompt, or the command that would run
ctrl+r Reindex now; offered once the index has gone stale
esc Back out of a confirmation, or close the history, or quit

The status line always names the index's age, colored green, yellow, or red as it
goes from fresh to stale to very stale. ctrl+r appears in the key hints, and works,
only once it has gone stale: it exits the picker, reindexes on the normal screen where
its progress can print, and reopens the picker on the result. Set autoReindexAfterHours
in the config file to have this happen on its own once the index crosses that age;
0 reindexes on every open.

The picker lays itself out against the terminal it is drawn in, so a narrow window
gets the same interface rather than a broken one:

The picker on an eighty column terminal, with the same layout at a smaller size

Commands

Command What it does
nekyia Open the interactive picker
nekyia search <query> Search from the terminal, with optional JSON or id-only output
nekyia blame <path> List recent sessions that touched this exact file
nekyia timeline [--dir <path>] What happened to files in a directory, in the order it happened
nekyia last Launch the newest visible session in this directory
nekyia index [--rebuild] Refresh fingerprints and changed session content
nekyia show <uid> Print a deterministic handover as Markdown
nekyia handoff <uid> --to <client> Start a fresh target client with the source session's indexed context
nekyia doctor [--sniff] Report clients, paths, size caps, unreadable transcripts, and unsupported stores
nekyia forget <uid> Remove one session and every searchable facet from the index
nekyia prune --missing Remove indexed sessions whose sources disappeared
nekyia exclude <glob> Add an index-time directory exclusion

--ids prints only the session ids, one per line, so a session you picked out by eye
can be handed straight to another command:

nekyia search "sse reconnect" --ids | head -1 | xargs nekyia show

Run nekyia --help for search filters, sort modes, limits, and command-specific options.

To continue work in another client:

nekyia handoff claude:<session-id> --to codex
nekyia handoff claude:<session-id> --to codex --dry-run
nekyia handoff claude:<session-id> --to codex --dry-run --json
nekyia handoff claude:<session-id> --to codex --intent review
nekyia handoff claude:<session-id> --to codex --note "focus on the retry logic"

Handoff starts a fresh session using the target's brief command and the source's
recorded directory (unless a custom manifest overrides it). It uses the last indexed
context; run nekyia index first if the source conversation has changed. It transfers
no native conversation state, tool state, or file snapshots, and does not restore a
historical branch. Treat the brief as historical context: current instructions and
the current repository take precedence. Same-client handoff is also allowed.

--max-chars <n> follows show's character budget (default 40,000). User prompts are
preserved even when the budget is zero or too small. Launching refuses a brief whose
command or argument text alone would exceed a conservative 128 KiB allowance,
measured in UTF-8 bytes; it never truncates prompts to make them fit. If this happens,
export with nekyia show <uid> and transfer the relevant context manually.

By default the target is told this is a handover to continue, the same framing
show produces on its own. --intent review asks the target to critique the
session's changes instead of extending them: look for bugs, missed edge cases, and
better approaches. --note <text> replaces that framing with your own instruction
(up to 2,000 characters) and cannot be combined with --intent. Either framing is
prepended to the brief and, like the rest of the mandatory header, is never dropped
to fit the character budget. The ctrl+t picker offers the same choice interactively:
r for review, n to type a note, plain enter to continue as before.

--dry-run prints the planned shell command without checking whether the target is
installed. --dry-run --json prints { cmd, args, cwd, briefChars }; --json requires
--dry-run. Both outputs include the brief in the arguments and are content exports,
which may contain private information or secrets retained in user prompts. Execution
also passes the brief through process arguments, visible where OS permissions permit.
The target client may send this context to its configured model provider and incur
token costs. Repeated handoffs can retain earlier briefs inside later prompts.

Supported clients

Support means the store format was exercised against real or fidelity-matched local
data, not guessed from a likely path. Resume means the selected ID can be passed to a
verified resume command. Search means Nekyia starts a fresh briefed session because
exact attachment was not confirmed.

Client Tier Command Nekyia runs
Claude Code Resume claude --resume <id>
Codex Resume codex resume <id>
Antigravity CLI, agy Resume agy --conversation <id>
GitHub Copilot CLI Resume copilot --resume=<id>
opencode Search opencode --prompt <brief>
Kilo Code Search kilo --prompt <brief>
Codebuff Search codebuff --cwd <cwd> <brief>

Kilo shares opencode's tested store format, but its executable was not installed during
command verification. opencode and Codebuff were exercised against real local IDs, but
the result did not prove attachment to the requested context. I do not call any of those
three resumable. Search-tier clients always start fresh briefed sessions. They never claim
to recover tool state or file snapshots, and sending a handover can cost tokens.

Fresh handoff commands and the scope of their verification are documented in
cross-client handoff notes. The Codebuff handoff
template invokes codebuff; current Freebuff does not accept an initial prompt.

How it works

Nekyia separates indexing into two phases. Discovery reads bounded metadata and stable
fingerprints. Hydration runs only for new or changed sessions, streams or projects the
relevant content, and commits metadata plus search facets atomically to SQLite.

Search weights titles, user prompts, and selected assistant prose differently, then can
blend relevance with recency. Fork chains collapse to one visible result. Tool output is
excluded because command results and file dumps are noisy, large, and likely to contain
private material that does not belong in search.

The index normally lives at ~/.local/share/nekyia/index.db; configuration lives at
~/.config/nekyia/config.json. Nekyia honours XDG_DATA_HOME and XDG_CONFIG_HOME.

Privacy and data retention

Nekyia makes no network requests. There is no network service, no API key, and no telemetry.
The handover is deterministic and makes no model call.

The index reads transcripts already on your disk and stores selected paths and text
locally. That indexed copy can survive deletion of the original transcript. You control
that retention explicitly:

  • nekyia forget <uid> purges one indexed session
  • nekyia prune --missing purges sessions whose source files disappeared
  • nekyia exclude '/work/private' adds an exclusion covering that directory and everything
    under it, expanding a leading ~ and resolving a relative directory against the one you
    ran it in, and the next nekyia index then deletes what was already indexed there,
    including sessions whose transcripts have since been deleted

exclude and hiddenClients are instructions rather than preferences, and the values
they fall back to are the permissive ones, so a config file Nekyia cannot read would
otherwise widen what it holds. Indexing refuses outright on a config whose exclusions
could not be honoured, before it writes anything, and names the file. Searching still
answers, because a typo should not cost you your history, but it says on stderr that the
config was not honoured. A malformed preference, such as halfLifeDays, is still just
ignored for that run.

Nekyia does not promise secret redaction or index encryption. Review show, doctor,
and JSON output before pasting it into a public issue.

Adding a client

User manifests live in ~/.config/nekyia/clients/*.json. Schema version 1 describes the
client roots, storage format, support tier, and optional launch templates. A minimal flat
JSONL manifest looks like this:

{
  "schema": 1,
  "id": "my-client",
  "name": "My client",
  "roots": ["~/.local/share/my-client"],
  "format": "jsonl-transcript",
  "tier": "search",
  "jsonl": {
    "glob": "sessions/*.jsonl",
    "variant": "generic",
    "generic": {
      "idFrom": "filename",
      "cwdPath": "cwd",
      "tsPath": "timestamp",
      "rolePath": "role",
      "textPath": "text",
      "userRoles": ["user"],
      "assistantRoles": ["assistant"]
    }
  },
  "brief": {
    "cmd": "my-client",
    "args": ["{prompt}"],
    "cwd": "{cwd}"
  }
}

A SQLite manifest can add "revision" to its sqlite block, naming a projected column
that moves whenever its session does, usually the one already aliased to ended_at. With
it each session is fingerprinted from its own row, so editing one session re-reads only
that session. Without it the whole database shares one fingerprint and any change re-reads
every session in it, which is slower and is the right default: declaring a revision the
store does not honour means edits nobody notices.

nekyia doctor --sniff looks for session-shaped stores without declaring them supported.
nekyia doctor --sniff --emit-manifest ./my-client.json writes a non-overwriting draft
for the first store it can describe. Inspect and test that draft before moving it into the
user manifest directory or contributing it.

Development

bun install --frozen-lockfile
bun run lint
bun run typecheck
bun run test
bun pm pack --dry-run

CI runs the frozen install, lint, typecheck, full suite, and package check on Linux and macOS.
Releases use Conventional Commits and Release Please.

Roadmap

These clients still need hands-on testing before I ship a built-in manifest: Aider,
Goose, Crush, Cursor CLI, Qwen Code, Continue CLI, Droid, Amazon Q Developer CLI,
Plandex, OpenHands, Amp, Warp Agent, Grok CLI, Rovo Dev, Auggie, Trae, Cline CLI,
and Zed.

I also plan compiled standalone binaries through bun build --compile for Linux and
macOS on x64 and arm64. They are not part of this pre-release, so Bun is required.

License

Nekyia is available under the MIT license.


Built by Aranea Development. In the Odyssey, Odysseus
digs the trench and the dead crowd forward; he holds them back until the one shade he
needs may speak. nekyia --version says the same thing in one line.

Reviews (0)

No results found