Skip to content
How sieve works: its parts and the messages between them
  1. The agent asks a question in plain words.
  2. The server reads the request and routes it to the tool.
  3. The router checks that the index matches the files.
  4. The loader reads the symbol graph from disk.
  5. The ranker scores the symbols and keeps the best.
  6. The agent gets exact files and lines, with no API key.
flowfig checked this figure against the code on 2026-10-06: 5 of 5 boxes defined; edges: 1 found, 0 not found, 3 unsure, 2 not checked Code at 7c475a3.

Sieve gives your coding agent exact files, lines and callers. It runs locally and needs no API key.

Six pixel mascots. Sieve, a kitchen sieve, is the default.

$ sieve ask "how does the dev server handle hot module replacement"
ask  how does the dev server handle hot module replacement · 8 hits

1  [packages/vite/] createServerModuleRunner  fn  packages/vite/src/node/ssr/runtime/serverModuleRunner.ts:143-160
   function createServerModuleRunner( environment: DevEnvironment, options: ServerModuleRunnerOptions = {}, ): ModuleRunner

2  [packages/vite/] handleHMRUpdate  fn  packages/vite/src/node/server/hmr.ts:411-679
   async function handleHMRUpdate( type: 'create' | 'delete' | 'update', file: string, server: ViteDevServer, ): Promise<void>

3  [packages/vite/] _createServer  fn  packages/vite/src/node/server/index.ts:513-1148
...

Install

curl --proto '=https' --tlsv1.2 -LsSf https://github.com/iamalvisng/sieve/releases/latest/download/sieve-cli-installer.sh | sh

The installer puts sieve in $CARGO_HOME/bin. Put that folder on your PATH.

Other channels:

brew install iamalvisng/tap/sieve
cargo binstall sieve-cli
cargo install --locked --git https://github.com/iamalvisng/sieve sieve-cli

See docs/guide/install.md for each operating system.

On vite (1,583 files), sieve ask answers in 158 ms median on an Apple M1 Pro. See Proof.

Then run two commands in your repo:

sieve build .
sieve ask "how does login work"

init writes only inside the repo. Only --global writes under your home folder.

Find out why code exists

sieve why <symbol> shows the decision records that link to a symbol. A record is an ADR file or a LEDGER.md entry with a - **Code:** line. Your existing ADR files work.

Sieve reads these decision folders: docs/decisions/, docs/adr/, adr/, and LEDGER.md. Sieve ships its own records in docs/adr/.

This is real output from the public Sieve tree:

$ sieve why savings_line
why savings_line  crates/sieve-savings/src/lib.rs:96
decision  docs/adr/adr-0004-savings-header.md:1  ADR 0004: Each query result opens with one savings line
          link: Code anchor
test  crates/sieve-savings/src/lib.rs:236  savings_line_names_the_given_product
test  crates/sieve-savings/src/lib.rs:248  test_savings_sieve_header_has_no_tally_instruction
...

What you get

The samples are real output from vite. A ... line marks cut output.

Find the code without grep

sieve ask returns ranked symbols with exact file and line. The --source flag inlines the code. sieve grep finds every match and groups each hit under its symbol.

See who calls a symbol

sieve callers lists the callers to a depth you choose. Each row gives the file and the line. callers and blast mark each edge as exact or inferred.

$ sieve callers handleHMRUpdate --depth 2
handleHMRUpdate  fn  packages/vite/src/node/server/hmr.ts:411-679
2 callers · 5 within 2 hops
├─ testRestartDuringHotUpdate  fn  packages/vite/src/node/server/__tests__/hmr.spec.ts:6-40
│  │  34: handleHMRUpdate(
│  └─ hmr.spec.ts  file  packages/vite/src/node/server/__tests__/hmr.spec.ts:1-56
└─ onHMRUpdate  fn  packages/vite/src/node/server/index.ts:908-915
   │  913: await handleHMRUpdate(type, file, server)
   ├─ onFileAddUnlink  fn  packages/vite/src/node/server/index.ts:917-953
   └─ onFileChange  fn  packages/vite/src/node/server/index.ts:955-969
[sieve] saved ≈ 20,282 tokens

See what a diff breaks before CI does

sieve blast lists what depends on the lines your diff changed. It also says if a test reaches the code. This sample ran after one edited line in handleHMRUpdate (hmr.ts).

$ sieve blast
your diff changes handleHMRUpdate · 1 symbol in 2 files · 1 of 1 reached by a test · working tree vs HEAD
3 callers affected within 2 hops
└─ onHMRUpdate  fn  packages/vite/src/node/server/index.ts:908-915
   ├─ onFileAddUnlink  fn  packages/vite/src/node/server/index.ts:917-953
   └─ onFileChange  fn  packages/vite/src/node/server/index.ts:955-969
1 test suite also references this code (not listed)
tests for handleHMRUpdate were not updated
ask for review  翠 (80 commits, 11d ago) · btea (4 commits, 28d ago)
not indexed  1 file: .gitignore

Read a file as an outline

sieve skeleton prints the outline of one file with line ranges.

$ sieve skeleton packages/vite/src/node/server/index.ts
packages/vite/src/node/server/hmr.ts · 42 symbols
    48-56  WsOptions  iface
    58-88  HmrOptions  iface
    90-97  HotUpdateOptions  iface
   99-105  HmrContext  iface
  107-111  PropagationBoundary  iface
  113-115  HotChannelClient  iface
  117-120  HotChannelListener  type  <T extends string = string> = ( data: InferCustomEventPayload<T>, client: HotChannelClient, ) => void
...

Sieve also has map. The command reference lists all commands.

Graph viewer

sieve viz serves a graph viewer in your browser.

Read intercept

Sieve answers a Read of a file from the index. A read with offset or limit passes unchanged.

Remembered reads

Sieve remembers each file the agent reads in a session. The second read of an unchanged file gets this note:

[sieve] a.ts is unchanged since your last read. Use that copy. If you no longer hold it, read again.

Sieve denies every second read of an unchanged file. The read after a deny passes. A changed file always passes.

Pane

MCP

sieve mcp serves the index to any MCP host over stdio. The server has seven tools: sieve_find_code, sieve_find_all, sieve_trace_calls, sieve_file_api, sieve_repo_map, sieve_check_freshness and sieve_why.

Register it with { "mcpServers": { "sieve": { "command": "sieve", "args": ["mcp"] } } }. See docs/guide/mcp.md.

Proof

Sieve 0.1.0 on an Apple M1 Pro with 16 GB of memory, macOS 26.5.2.

Claim Repo and commit Number Method
Cold build ripgrep 3fce3b5 (111 files) 0.73 s Median of 3 builds, each on a fresh copy.
Cold build vite 10033218 (1583 files) 1.83 s Median of 3 builds, each on a fresh copy.
Warm build ripgrep 3fce3b5 0.31 s Median of 5 builds with no change.
Warm build vite 10033218 0.80 s Median of 5 builds with no change.
ask latency ripgrep 3fce3b5 62 ms median, 101 ms max Wall time of one sieve ask process. 30 timings: 10 questions, 3 runs each.
ask latency vite 10033218 158 ms median, 185 ms max The same method.
Exact cross-file calls vite 10033218 1,232 of 1,232 match the TypeScript compiler Name-level match. Inferred calls are not counted.

docs/guide/benchmarks.md gives the method and the questions, so you can repeat each run.

Languages

Sieve parses TypeScript, JavaScript, Python, Go, Java, Kotlin, Swift, PHP and R natively. It parses 14 more with a generic parser. It reads script blocks in Vue, Svelte and Astro files. Exact cross-file links cover named relative TypeScript and JavaScript imports only. See docs/guide/languages.md.

Local only

Sieve runs on your machine. Sieve sends no telemetry and makes no network call for a query. See ADR 0001, docs/guide/privacy.md and SECURITY.md.

When not to use Sieve

  • Sieve links calls across files as exact only for named relative TypeScript and JavaScript imports. Other cross-file calls are Inferred. Treat them as hints. See ADR 0002.
  • Sieve has not measured token savings in a real agent session.
  • There is no Windows build in v0.1.0.

The FAQ lists more limits.

Docs

Contributing

Read CONTRIBUTING.md before you open a pull request. Report a security issue as SECURITY.md describes. The changelog lists each release.

License

Sieve uses the MIT license or the Apache-2.0 license, at your choice. See LICENSE-MIT and LICENSE-APACHE. Third-party notices are in THIRD_PARTY.md.

Read the code.

Open the repository