Skip to main content

Silica

Retrieval tools for coding agents. No model in the loop.


Point Silica at a folder of markdown, code, PDFs or office files. The harness you already use (Claude Code, Codex, opencode, DeepSeek Harness, or a shell) gets five tools that return located evidence: a path, a section, a line, a window of text, and the numbers to judge it by. Silica never answers, summarises, plans or remembers for you. The harness owns the loop.

Tool Returns
silica_files the inventory and what the index did with each file: indexed, changed, excluded, failed, unconverted
silica_search ranked passages: path, section, line, raw BM25, matched terms, coverage, and the query terms absent from the corpus
silica_read a slice by lines or by heading (a page, in a PDF), the outline, and a version to carry forward
silica_code_pack an AST context pack for one source file inside a character budget
silica_write_note one atomic write, linted for structure and unresolved wikilinks

The contract, the reply shapes and the acceptance checks are in TOOLS.md. Nothing on that page needs an API key, a model or a network.

Install

uv tool install 'silica-core[mcp]'   # or: pipx install 'silica-core[mcp]'
silica setup claude                  # or: codex, opencode, dsh

The package is silica-core, the command is silica, the tools are silica_*: the distribution carries the name, the code keeps the namespace.

setup registers the MCP server in the client's own config at user scope. Every session then serves the folder the client was opened in. To serve another root, pass --vault DIR in the server entry, or export SILICA_VAULT in the client's env block; a .env file is not enough on purpose.

A PDF with a text layer is searched as it is: the index reads the layer itself, one section per page, so a hit reads p. 7 and silica_read serves that page alone. No conversion, no .md written beside it. The reply also carries extract_path, the extracted text on disk, for grep and the harness's own reader — the line numbers there are the ones silica_read serves. A scan has no text layer and reads as unconverted until you convert it.

Extras: [connect] adds the Obsidian bridge, [all] both. The converters for PDF (headings, figures), DOCX, EPUB, FB2, RTF, XLS and ODF need no extra. Scanned PDFs, images, PPTX and XLSX go through MinerU when it is on your PATH; audio and video need ffmpeg and a speech-to-text endpoint (SILICA_STT_BASE_URL). silica doctor says which lanes you have.

Docker

No image is published. The Dockerfile builds one, and CI builds and smoke-tests it on every push, so it stays runnable:

docker build -t silica-core .
docker run --rm -i -v /path/to/vault:/vault silica-core                 # the MCP server over stdio
docker run --rm -v /path/to/vault:/vault silica-core search "compaction" -k 5

The container serves /vault and keeps everything it derives — index, ledger, checkpoints — under /data, which is $HOME inside the image: mount a volume there or the index is rebuilt on every run. The lanes that need a system binary (MinerU, ffmpeg, soffice) are deliberately not in the image; docker run --rm silica-core doctor reports them missing, and the comments in the Dockerfile say where to add the ones you use.

From the shell

Every subcommand prints the same JSON the MCP tool returns, so a harness with a shell needs no MCP at all.

silica index                                   # build or refresh the index (searches do it on first use)
silica search "incremental index updates" -k 5
silica read papers/lsm-trees.md --section "3 Compaction"
silica files --status unconverted              # what the index could not read
silica import papers/lsm-trees.pdf             # writes papers/lsm-trees.md beside the PDF (which then wins over the text layer)
silica write-note notes/decision.md --body-file - < decision.md
silica code-pack src/search/index.py --budget 12000
silica mcp --extended                          # also serve the tables and link tools

How search says no

A search returns hits even when the corpus does not answer, because a ranked list always has a top. What tells the two apart:

  • coverage: the share of the query's idf mass the hit's matched terms carry. Near 1, every rare term matched; near 0, only the common words did.
  • terms_absent: query terms that occur nowhere in the corpus.
  • matched_terms: which words this hit actually contains.
  • dominance: the top hit's score over the runner-up's, null when there is no runner-up. Near 1 the pool is flat and one passage is not enough; high, and the top hit stands alone.

Measured on 254 converted papers (22 MB): the answered questions scored 0.69 to 1.00 on their top hit, a question the corpus does not cover scored 0.44. No boolean is derivable from lexical signals alone, so Silica exposes the numbers and the harness decides to stop, read, or rephrase.

dominance does not substitute for coverage, and the same corpus shows why: the question it cannot answer scored the highest dominance of the set, 1.29 against 1.07 to 1.16 on the answered ones. A query the corpus does not cover still has one clear top — that is what a ranked list does. Coverage says whether to trust the pool; dominance says whether one hit out of it is enough.

Ranking is BM25 over documents, then over the heading sections of the top documents, at most two sections per document, with each hit's densest window. The index is one JSON file per root under ~/.silica/index, built in seconds and refreshed by mtime.

The optional REPL

silica repl is the reference harness: a plain agent loop over the same tools, for a folder where no coding agent is running. It is the only surface that needs a model, and the model is any OpenAI-compatible chat endpoint:

export SILICA_MODEL=openrouter/deepseek/deepseek-chat OPENROUTER_API_KEY=   # hosted
export SILICA_MODEL=lmstudio/qwen3-14b                                      # or local: lmstudio/…, ollama/…
silica repl

SILICA_PROVIDER_BASE_URL and SILICA_PROVIDER_API_KEY point a bare model id at any other endpoint. silica mcp never needs any of this.

Extended tools

silica mcp --extended adds the tabular census (silica_tables, silica_query_table: DuckDB over CSV, XLSX and friends, schema in every reply) and the wikilink tools (silica_links, silica_backlinks, silica_orphans, silica_unresolved) over the same root.

Obsidian

silica connect hosts the bridge the Obsidian plugin dials into, so writes can land through Obsidian's own vault API while the app is open. The five core tools do not need it: they read and write the folder directly.

Not included, on purpose

No LLM client, no memory lane, no session capture, no hook that injects text into a prompt, no summaries, no undo journal. Undo is git. The private product this core is cut from keeps those lanes.

Development

git clone https://github.com/kiycoh/silica-core.git && cd silica-core
uv sync --extra dev --extra mcp
uv run pytest -q
SILICA_BENCH_CORPUS=/path/to/markdown uv run pytest tests/test_retrieval_check.py -s   # the acceptance check
uv run lint-imports && uv run mypy silica && uv run ruff check silica tests

License

MIT. See LICENSE.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

silica_core-0.7.1.tar.gz (762.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

silica_core-0.7.1-py3-none-any.whl (241.0 kB view details)

Uploaded Python 3

File details

Details for the file silica_core-0.7.1.tar.gz.

File metadata

  • Download URL: silica_core-0.7.1.tar.gz
  • Upload date:
  • Size: 762.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for silica_core-0.7.1.tar.gz
Algorithm Hash digest
SHA256 fc8283c8ba608600061c2a19c05374a834a7366155935d9d8d27abebcecccfb0
MD5 633c4b5ca1644e209b673fffdb736d47
BLAKE2b-256 b8c2dfc4936112fe2dc25e44eff957bffa8908837a372b70d0de45bdc316e695

See more details on using hashes here.

Provenance

The following attestation bundles were made for silica_core-0.7.1.tar.gz:

Publisher: release.yml on kiycoh/silica-core

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file silica_core-0.7.1-py3-none-any.whl.

File metadata

  • Download URL: silica_core-0.7.1-py3-none-any.whl
  • Upload date:
  • Size: 241.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for silica_core-0.7.1-py3-none-any.whl
Algorithm Hash digest
SHA256 cadec4882dd1d6f6cbbbb0a407fcfc9dd4392c3cb03cdc58ac81a6bffbbc63a8
MD5 af3a41eb9109db76eb9eea4ec8050e7c
BLAKE2b-256 cea2aa312677372d2fdeb88ef6a191a373127214e79c0881676a0bc1327ec005

See more details on using hashes here.

Provenance

The following attestation bundles were made for silica_core-0.7.1-py3-none-any.whl:

Publisher: release.yml on kiycoh/silica-core

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.8.2

2 files

0.8.1

2 files

0.8.0

2 files

0.7.4

2 files

0.7.3

2 files

0.7.2

2 files

This release

0.7.1 This release

2 files

0.7.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page