Repository navigation
Releases: jrapakko/scree
Release list
v0.2.0
Code vocabulary routing for auto
auto, the default search mode, now also runs hybrid (vector plus keyword search) when a query names something from the repo's code, even a name with no _ or digit, such as psycopg or PageFetcher. Before, auto caught only words with a _ or digit, such as SCREE_FIRST_SYNC_MB or R7-Q2.
Each sync builds a vocabulary of names from the repo:
- Dependency names from
requirements*.txt,pyproject.toml,package.json,go.modandCargo.toml. - Mixed-case names from imports and declarations in Python, JavaScript, TypeScript and Go, such as
PageFetcheranduseState.
Privacy
- Code is read for names only, under the same
.gitignore,.screeignore, size and symlink rules as markdown. - Only the lowercased names are stored, in the repo's local index. Code is never chunked, embedded, sent to the API or returned by
read_doc. - Names come only from where code declares or imports them, never from values, strings, comments or docstrings.
- Code under hidden folders such as
.claude/and.github/adds no names, and vendored folders such asnode_modulesandvendorare skipped. - A symlink must point to a file of its own kind: a
.mdlink to a source file is refused.
Routing quality
- A stoplist of about 350 common words keeps plain questions on
semantic. It covers question words, packages named after ordinary words (requests,markdown,sync) and mixed-case plain words (setUp,FileName). - On two repos with code and docs, most questions naming code switched to
hybrid, and no plain question did. - A word the stoplist misses can still send a plain question to
hybrid.-mode semanticis always available.
Limits
- At most 20,000 source files are read per sync. Each file adds at most 2,000 names, and the vocabulary holds at most 100,000.
- Unchanged files aren't parsed again. Names are rebuilt when the extractor changes.
- The vocabulary refreshes on a full sync: at startup, on takeover, on
reindex, or on a resync. The file watcher doesn't re-read code between syncs.
scree doctor
doctor reports the vocabulary size and how many names also appear in the notes. doctor -v prints a sample, showing only names that also appear in the notes.
Upgrading
- The index schema moves to v4. It upgrades automatically when an index is opened, and the next sync fills in the vocabulary.
- Restart Claude Code sessions, or reconnect scree with
/mcp, so they run the new binary. An older binary can still open a v4 index, but it doesn't keep the vocabulary.
Other
- A test that timed out on slow macOS runners now has a longer deadline.
- The docs at https://scree.jrpko.dev are updated for this release.
Full changelog: v0.1.0...v0.2.0
Changelog
- f00d335 Docs: v0.1.0 is cut; drop it from the registry to-do
- 5dc9a9c Route auto to hybrid on names from the repo's code
- cc10a9c Tests: give the stale-path writer test 15s
- eda5346 Vocab: close the markdown-symlink leak and tighten the vocabulary
- b38c04c Vocab: count a code name only when the notes mention it
- 27903f2 Vocab: route on the vocabulary alone; gate only doctor's sample
- 756baa9 Vocab: take names only from name positions
v0.1.0
scree v0.1.0
First release. scree gives Claude Code search over a repo's markdown: by meaning, and by exact identifiers. It runs locally as an MCP server, and each repo opts in.
Highlights
- Per-repo, opt-in. Register scree in a repo's committed
.mcp.jsonwithclaude mcp add scree --scope project -- scree mcp. Each repo gets its own index, stored outside the repo. - Search that fits how docs are used.
auto(the default) uses semantic search for plain questions, and adds keyword search when a query contains an identifier likeMAX_RETRIESorR7-Q2.semantic,keywordandhybridare available explicitly.keywordneeds no API call.
- Precise hits.
- Each result gives its file, heading trail and line range (
docs/api.md:486-492). - If the file changed since indexing, the range is relocated, or the hit is marked
stale. - Duplicate copies fold into one hit, listed under
also=.
- Each result gives its file, heading trail and line range (
- Respects your repo.
- Follows
.gitignorewith git's rules, including nested files,info/excludeand your global excludes. - Indexes markdown in
.github/,.claude/,.cursor/and similar folders at the repo root. - Supports
.screeignoreandscree: ignorefront matter. scree run doctor -vshows what's indexed and ignored, with a cost estimate.
- Follows
- Stays current. One session per repo indexes in the background and watches for changes; other sessions share the index.
- Cheap and light. About $0.0025 per MB of markdown to index once, through OpenRouter with zero data retention requested. About 13–20 MB of memory per process. A single static binary.
Install
- Download the archive for your platform below, or
docker pull ghcr.io/jrapakko/scree:0.1.0. - Put
screeon your PATH (for example~/.local/bin). - Write
~/.config/scree/env(mode 600) containingOPENROUTER_API_KEY='…'. - In a repo:
claude mcp add scree --scope project -- scree mcp, then commit.mcp.json.
Full guide: https://scree.jrpko.dev/getting-started.html
Security notes
- The settings file is the only source of configuration.
scree mcpre-runs scree with a clean environment. - scree takes the indexed folder from where Claude Code started it, refuses folders that haven't opted in, and never indexes your home directory.
- Approving scree in a repo's
.mcp.jsonmeans trusting that repo: Claude Code applies the repo'senv, includingPATH, which decides which program runs. Only approve it in repos you trust. Details: https://scree.jrpko.dev/security.html
Known limitations
- On Windows,
scree mcpandscree runaren't supported yet. Runscree servedirectly. - On macOS, the binary links the system library dynamically, so
DYLD_INSERT_LIBRARIESfrom a repo's.mcp.jsoncan reach it. That falls within the repo-trust note above. - Docker on SELinux hosts needs
SCREE_MOUNT_OPTS=ro,z, which relabels the mounted folder.
Checksums are in checksums.txt. Licenses for bundled dependencies are in each archive under THIRD_PARTY_LICENSES/.
Changelog
- bdd52c9 Add MIT license, CI, and GoReleaser/GHCR release workflow
- 8c339c0 Docs: match the code before v0.1.0
- 0fd9bac Fix pass: ignore rules, red-team fixes, ZDR, Docker, key-safe wrappers
- de7d0a4 Initial scree: semantic search over markdown notes via MCP
- e76e251 Merge branch 'main' into per-repo
- d1af508 Merge branch 'main' into per-repo
- 5ff78d5 README: add Quick start; keep the API key out of shell profiles
- 107e772 SPEC: record open items, including local and LAN embedding models
- 1c7d72e Tests: don't expect one watcher event per file on macOS
- aa579d4 Tests: pass when the temp dir is behind a symlink (macOS)
- cb88f0a Use invented example identifiers in tests and docs
- fa35156 Wrappers read the settings file as data; scrub the key before truncating
- 7f14b84 Wrappers: re-exec once in an empty environment before running anything
- 41fad78 Wrappers: the settings file is the only source of configuration
- a337551 per-repo step 4: folder from -notes or CLAUDE_PROJECT_DIR, per-folder index
- f298b98 per-repo step 4b: canonical on-disk names, NFC and case folding, read races
- b97e7d1 per-repo step 4c: file rules beat folder negations, looser front matter, search re-checks
- 66a5ecf per-repo step 5: writer lock per index, background sync in serve, watcher split
- be4f2d1 per-repo step 5c-1: no symlinked git files, no echoed content, serve uses only the repo
- a369232 per-repo step 5c-2: FIFO-safe reads, bounded shutdown, trust only your own .git, fast Canonical
- e526434 per-repo step 6-1: search_docs/read_doc, line ranges, cost estimate, first-sync cap
- 17bb689 per-repo step 6-2: current line ranges for changed files, duplicate collapse
- 4def87d per-repo step 6b: hybrid search (FTS5 keyword index + vectors, RRF)
- c2a2afe per-repo step 7: scree indexes [-prune]
- 2967301 per-repo step 8: final README and SPEC; settings file always from passwd home
- 5ba5bc3 per-repo steps 1-3: git-style ignores, hidden-folder allowlist, watcher pruning
- ee50679 per-repo: final fix round (red-team round 4, final verifier)
- d56292d policy: let TestUnsafeName run where the filesystem refuses a name
- 6a575f9 policy: map paths that reach the notes folder through another symlink
- 0425233 scree mcp / scree run: the launchers move into the static binary
- fcd92a3 scree-mcp-docker: never pull the image
- 7c56901 search: auto is the default mode