deterministic · offline · $0 to index

Stop your coding agent reading whole files.

seonix turns a repository into a typed code graph your agent can ask directly — paired with a short guidance note, it edits from turn 1 instead of fishing through the repo. Built offline, $0.

75% of seonix-ask-guidance runs actually call the live ask tool this cycle, up from 5% the cycle before pairing it with guidance
6–28% input-token reduction on every measured cell, both models tested, zero solve-rate regression
$0 to build the graph: no API keys, no cloud, no telemetry

Status, 2026-07-28. The shipped default pairs the live seonix_ask MCP tool with a token-discipline guidance file, measured against an out-of-the-box agent given the same guidance. No cell clears the ≥50% bar yet (ts-hono·response-time Haiku 13%, Sonnet 28%; eshoponweb·order-service Haiku 6%, Sonnet 12%), but every cell is a real, positive reduction with no solve-rate regression. Full grid, traces, and method in BENCHMARK_0.11.10 ↗.

quickstart →
Star

Paired-arm benchmark: same model pin, N≥3 runs, mean input tokens over the tasks both arms solved, index cost counted separately, no drop in solve rate. Any win depends on the model and the codebase. A leaner agent, or a repo small enough to hold in context, has less to displace. Full method: BENCHMARKS ↗.

How it works

seonix reads your repository into a typed graph: the modules, classes, functions, methods and attributes a change touches, and how they connect. It follows the published seonix schema.

  1. 1 · Build the graph

    Point seonix at a repository and it derives that typed graph offline. Same commit → the same graph every time. Nothing leaves your machine.

  2. 2 · Find the change site

    From your task description, seonix ranks the parts of the graph the change touches, with no human-chosen target. Already know the file? Hand it in directly.

  3. 3 · Hand over the digest

    seonix renders a bounded edit digest (the signatures, call sites and insertion regions your agent needs) and hands it over at the start of the session. The agent edits from turn 1 instead of exploring; the render is deterministic and costs $0.

See it run

One real task, run twice on the same rig that produces every number here. It shows the mechanism on one cell. The grid below is the evidence.

=== proof-demo: otb vs seonix, one real task, one cheap model, n=3 (mean) ===
suite=eshoponweb  task=order-service-total  model=claude-haiku-4-5

$ node bench/run.mjs --suite eshoponweb --arms otb --models claude-haiku-4-5 --runs 3 --instance order-service-total
  mean turns=9.0  mean input_tokens=288,796  mean cost=$0.0660  errors=0/3
  run 1 actions (representative):
  · Agent()
  · TaskOutput()
  · Bash("find <repo> -type f -name "*.cs" | grep …")
  · Read(Interfaces/IOrderService.cs)
  · Read(Services/OrderService.cs)
  · Read(Specifications/OrderWithItemsByIdSpec.cs)
  · Read(Interfaces/IOrderService.cs)
  · Read(Services/OrderService.cs)
  · Edit(Interfaces/IOrderService.cs)
  · Edit(Services/OrderService.cs)

$ node bench/run.mjs --suite eshoponweb --arms seonix --models claude-haiku-4-5 --runs 3 --instance order-service-total
  mean turns=6.0  mean input_tokens=263,790  mean cost=$0.0659  errors=0/3
  run 1 actions (representative):
  · Edit(Interfaces/IOrderService.cs)
  · Read(Interfaces/IOrderService.cs)
  · Edit(Interfaces/IOrderService.cs)
  · Read(Services/OrderService.cs)
  · Edit(Services/OrderService.cs)

--- headline (mean of 3 runs per arm) ---
input tokens:  otb 288,796  →  seonix 263,790  (-8.7% fewer)
turns:         otb 9.0  →  seonix 6.0
billed cost:   otb $0.0660  →  seonix $0.0659

(one task, n=3 per arm, one cheap model — illustrative, not the full benchmark grid; solve-status is graded by the real pipeline, not this quick script — see the results table above for the measured, paired-arm numbers this site actually cites.)

Repeatable: npm run proof reruns both arms for real and regenerates this capture. Nothing here is staged or hand-edited.

Ask the graph a question, from a terminal, with no model in the loop:

$ node packages/seonix/bin/cli.mjs cli seonix_ask '{"query":"which modules import walk.mjs"}' | jq -r '.matches[].label'
packages/seonix/src/cs_treesitter.mjs
packages/seonix/src/extract.mjs
packages/seonix/src/java_treesitter.mjs
packages/seonix/src/jsts_tsc.mjs
packages/seonix/src/manifest.mjs
scripts/verify-counts.mjs

seonix_ask runs tmct's deterministic, no-LLM engine over the graph. It returns JSON, so it pipes straight into jq, a script, or another tool.

Or hold a conversation. A real seonix chat transcript against this repo's own index:

tmct> which modules import walk.mjs
packages/seonix/src/cs_treesitter.mjs and packages/seonix/src/extract.mjs and packages/seonix/src/java_treesitter.mjs and packages/seonix/src/jsts_tsc.mjs and packages/seonix/src/manifest.mjs and scripts/verify-counts.mjs.

tmct> where is buildContextBundle defined
function buildContextBundle() is defined in packages/seonix/src/server.mjs at lines 139-261.

tmct> when did walk.mjs change
packages/seonix/src/walk.mjs was last touched by commit 541d91db47f3 on 2026-07-04 ("feat(seonix): seonix.toml config loader […]"); 2 earlier commits recorded.

seonix chat runs tmct (@polycode-projects/the-mechanical-code-talker), a deterministic no-LLM chatbot, over seonix's graph. Every answer is grounded in the graph or an honest miss — no model in the loop.

Benchmarks

Current cycle — Benchmark 0.11.10

The shipped default pairs the live seonix_ask MCP tool with a token-discipline guidance file (seonix-ask-guidance), measured against an out-of-the-box agent given the same guidance (otb-guidance), environment-isolated so a host's own global config can't leak into either side. No cell clears the ≥50% bar yet, but every cell is a genuine, positive reduction with no solve-rate regression — and the tool actually gets used now: seonix_ask fired in 75% of runs, up from 5% the cycle before pairing it with guidance. Full method, traces, and negative results in BENCHMARK_0.11.10 ↗.

Mean total_input_tokens per solved run (thousands, incl. cache reads), N=5. otb = otb-guidance (out-of-the-box agent + the token-discipline guidance file); ask = seonix-ask-guidance (the live seonix_ask MCP tool + the same guidance file). Each ask cell shows % input tokens saved vs the same-row otb (negative = seonix used more), the mean token count beneath. Every number here is traceable to a record in results/raw-0.11.10/; full method and per-cell traces in BENCHMARK_0.11.10 ↗.
Task Haiku 4.5 Sonnet 4.6
otbask otbask
TypeScript — hono
ts-hono-response-time-middleware 1598k13%1383k 1000k28%720k
C# — eShopOnWeb
cs-eshoponweb-order-service-total 585k6%549k 326k12%288k

All four cells solved 5/5 both arms — no solve-rate regression anywhere. seonix_ask calls per run (mean of 5): ts-hono Haiku 1.8, Sonnet 0.6; eshoponweb Haiku 1.8, Sonnet 4.0. 15 of 20 runs called it at least once, up from 1 of 20 the cycle before pairing it with guidance — the tool is used now; the remaining gap is that using it once doesn't reliably keep the rest of the run cheap. Trace appendix in BENCHMARK_0.11.10_TRACES ↗.

Quickstart with Claude Code

seonix is a Node package (ESM, Node ≥ 24) that shells out to Python 3 and git, both on PATH. Four steps take Claude Code from grepping the tree to editing from turn 1.

  1. Install the seonix CLI:

    npm i -g @polycode-projects/seonix
  2. Build the graph (deterministic, offline, $0):

    seonix cli index_repository '{"repo_path":"/abs/path/to/repo"}'

    This writes the typed code graph to .seonix/graph.json (plus a .seonix/TOOLS.md tool catalog). Same commit → byte-for-byte identical graph.

  3. Render a bounded edit-digest for the modules a task touches and save it where the agent can read it:

    # which modules does the change touch? (ranked, no LLM)
    seonix cli seonix_locate '{"repo_path":"/abs/path/to/repo","query":"<your task>"}'
    
    # render the digest for those modules → save it under .seonix/
    seonix cli digest '{"repo_path":"/abs/path/to/repo","modules":["src/pkg/module.py"]}' > /abs/path/to/repo/.seonix/digest.txt
  4. Put the digest in front of the agent at session start. Wire a Claude Code SessionStart hook that adds the rendered digest to the session context (or paste it at the top of a claude session):

    # .claude/settings.json — inject the digest once, at session start
    { "hooks": { "SessionStart": [ { "hooks": [
      { "type": "command", "command": "cat .seonix/digest.txt" }
    ] } ] } }

    The digest is in context from turn 1, so the agent edits without exploring first. No MCP server, no tool loop: the saving comes from the digest arriving up front rather than from an interactive round-trip.

Copy-paste setup

The same four steps as one block per tool, with the permission rules that let the agent run seonix without prompts.

Claude Code

# install + index (offline, $0)
npm i -g @polycode-projects/seonix
cd /path/to/your/repo
seonix cli index_repository "{\"repo_path\":\"$PWD\"}"

# locate the change site, render the digest
seonix cli seonix_locate "{\"repo_path\":\"$PWD\",\"query\":\"<your task>\"}"
seonix cli digest "{\"repo_path\":\"$PWD\",\"modules\":[\"src/pkg/module.py\"]}" \
  > .seonix/digest.txt

# .claude/settings.json — inject at session start; allow seonix
# to run un-prompted via the permissions framework
cat > .claude/settings.json <<'JSON'
{
  "permissions": {
    "allow": ["Bash(seonix:*)", "Read(.seonix/**)"]
  },
  "hooks": {
    "SessionStart": [
      { "hooks": [ { "type": "command",
          "command": "cat \"$CLAUDE_PROJECT_DIR/.seonix/digest.txt\" 2>/dev/null || true" } ] }
    ]
  }
}
JSON

The hook puts the digest in context from turn 1; the permissions.allow rule lets the agent re-run seonix (re-index, re-locate, re-render) without an approval prompt.

GitHub Copilot (VS Code agent mode)

# install + index + digest — same commands
npm i -g @polycode-projects/seonix
cd /path/to/your/repo
seonix cli index_repository "{\"repo_path\":\"$PWD\"}"
seonix cli digest "{\"repo_path\":\"$PWD\",\"modules\":[\"src/pkg/module.py\"]}" \
  > .seonix/digest.txt

# .github/copilot-instructions.md — Copilot reads this file
# automatically at the start of every chat/agent task
cat >> .github/copilot-instructions.md <<'MD'
Before exploring the codebase, read `.seonix/digest.txt` — it is a
pre-built edit digest (signatures, call sites, insertion regions) for
this repository. Re-render it with:
`seonix cli digest '{"repo_path":"<abs repo path>","modules":[...]}'`
MD

# VS Code settings.json — allow seonix in the terminal
# tool without a confirmation prompt
"chat.tools.terminal.autoApprove": { "seonix": true }

Copilot has no session-start hook, so injection is by reference: the instructions file (read automatically) points the agent at the digest, and the terminal auto-approve setting lets it run seonix itself without a prompt. Check the setting name against your VS Code version; the terminal allow-list has been renamed between releases.

Or paste one prompt into chat. It works for Claude Code, Copilot, or any tool-calling agent; the agent reads its own capabilities and skips whatever doesn't apply:

Install seonix globally (`npm i -g @polycode-projects/seonix`), then index
this repository by running `seonix cli index_repository` with
`repo_path` set to this repo's absolute path. Render its edit digest to
`.seonix/digest.txt` with `seonix cli digest`.

Then configure yourself to load that digest automatically, using
whichever of these applies to you — check your own docs/settings and
skip what doesn't exist:
- If you support a session-start hook (e.g. Claude Code's
  `.claude/settings.json` → `hooks.SessionStart`), add one that `cat`s
  `.seonix/digest.txt` into context (no-op if the file is missing), and
  add `"Bash(seonix:*)"` + `"Read(.seonix/**)"` to `permissions.allow`
  so you can re-index/re-locate/re-render yourself without a prompt.
- If you don't have a hook but read a standing instructions file (e.g.
  Copilot's `.github/copilot-instructions.md`), append a note there
  telling yourself to read `.seonix/digest.txt` before exploring the
  codebase, and enable running `seonix` in your terminal/tool-call
  allow-list without a confirmation prompt (e.g. VS Code's
  `chat.tools.terminal.autoApprove`).

Verify by starting a fresh session and confirming the digest text is
present in context or referenced correctly.

Prefer an interactive tool? seonix also runs as a local server. The digest path above is the recommended one, and the one the benchmarks measure. Everything runs against your local checkout with no network calls. The graph rebuilds from source, so keep it out of version control.

Configure & tune

No server to run

The recommended path hands the agent one pre-rendered digest and runs it with no server attached. That is the shape the benchmarks measure and the one that deploys cleanly. An interactive mode is there if you want it.

Automatic, or point it yourself

seonix picks the change site straight from your task description, with no human in the loop. Already know the file? Name it directly and skip the search.

Deterministic & cache-stable

The same commit always produces the same graph, so rebuilds are reproducible and the digest stays cache-stable; prompt caching keeps repeat turns cheap.

Cost & privacy

Building the graph and querying it cost $0 beyond CPU and disk: no model calls, no API keys, no cloud. seonix runs entirely on your machine and never phones home.

seonix, indexing itself

The graph below is a live seonix viz render of seonix's own code graph, the same typed-edge structure it builds for any repo you point it at.

Visualisation loads here. If it doesn't, open the graph directly ↗ or view the commit timeline.

Install seonix