Setup
Claude Code
One command configures shire globally for all projects:
shire init --global
This creates:
~/.claude/shire.toml— shared config withdb_path = "~/.claude/shire/{repo}/{worktree}/index.db"(auto-namespaced per repo and worktree)mcpServers.shirein~/.claude.json— serves the index viashire servePostToolUsehook in~/.claude/settings.json— auto-rebuilds the index after file edits (Edit,Write,NotebookEdit,Bash)~/.claude/rules/shire.md— rules file guiding Claude Code to prefer Shire tools
The {repo} placeholder is replaced with the repository directory name at runtime, and {worktree} with the worktree name (or _primary for the main checkout), so each repo and worktree gets its own index file automatically.
After running shire init --global, open any repo and run:
shire build
The index is ready. Claude Code will automatically use it via the MCP server.
Interactive setup
Run in a terminal, shire init asks its questions in sections:
- Index: the install scope, rebuild strategy, database path, whether to gitignore the index directory, and extra directories to exclude.
- Extras: one checklist (space toggles an item, enter confirms):
- the cross-reference tools
- the rules file
- the
~/.claude/CLAUDE.mdguidance - the Claude Code status mod
- Review: lists every file it is about to write, then asks Apply these changes?
Answering no writes nothing.
- If
shire.tomlalready exists, you are asked first whether to overwrite it. Answer no to keep it and still set up the rest.
- If
--yes (or running without a terminal) skips the questions and uses the defaults.
Rules file
shire init creates ~/.claude/rules/shire.md with guidance on when to use Shire tools vs Grep/Glob. This helps Claude Code default to Shire for codebase searches, so you spend fewer tool calls on broad exploration.
If it already exists, shire init leaves it untouched — with one exception: turning on the cross-reference index (symbols.references_enabled) for a repo that already has a rules file appends the extra reference-tools guidance in place, so your other customizations are preserved.
CLAUDE.md integration
In interactive setup this is the Search guidance in ~/.claude/CLAUDE.md item in the
Extras checklist, checked by default. If selected, it appends a one-liner to ~/.claude/CLAUDE.md directing Claude Code to prefer Shire MCP tools over Grep/Glob for code search. The line is idempotent — running init again won’t duplicate it. If ~/.claude/CLAUDE.md doesn’t exist yet, it creates the file.
Claude Code status mod (experimental)
In interactive setup this is the Claude Code status mod item in the Extras checklist,
unchecked by default. Checking it, or passing --mod, installs it (--mod and --no-mod both answer the question, so the item is left out of the checklist). It is a Claude Code
mod
that polls shire status --json and shows index health in Claude Code’s status
line (for example shire ● 412 pkgs · 38.2k syms · 4m ago), shows a toast when something
changes (new build failures, an interrupted build, the watch daemon stopping), and adds a
/shire pane with rebuild buttons.
The mod is always installed for your user, even from a project-level shire init. Claude
Code loads extra plugin folders only from CLAUDE_CODE_PLUGIN_DIRS in ~/.claude/settings.json,
never from a project’s settings, so a cloned repository cannot turn it on. shire init writes
the mod’s files, which are compiled into the shire binary, to ~/.claude/shire-mod/shire-status/
and adds that folder to env.CLAUDE_CODE_PLUGIN_DIRS, keeping any folders already listed there.
New Claude Code sessions pick it up.
shire installrefreshes an installed mod’s files, so they keep matching the binary after an upgrade. It never installs the mod, and never touches the settings: if you removed the folder fromCLAUDE_CODE_PLUGIN_DIRSto switch the mod off, it stays off.shire uninstallremoves the folder and its entry inCLAUDE_CODE_PLUGIN_DIRS.
The mod uses Claude Code’s early-access mod API, which may change between Claude Code releases.
If a Claude Code update breaks it, Claude Code names the mod in the transcript, and
shire uninstall, or deleting the folder, turns it off.
Terminal output
shire init uses styled terminal output to show what it does:
- ✓ (green) — a file or config entry was created or updated
- – (dimmed) — a file or config entry already exists, skipped
- Section headers appear in cyan
Most file writes (.gitignore, CLAUDE.md, settings.json, .mcp.json, ~/.claude.json) use atomic writes — content is written to a temporary file first, then renamed into place. This prevents partial writes if the process is interrupted.
Project-level setup
To create a shire.toml in the current repo instead of globally:
shire init
This generates a minimal shire.toml (just db_path; everything else uses built-in defaults — see Configuration), writes the MCP server config to .mcp.json, and (in hook mode) a PostToolUse hook to .claude/settings.json plus .claude/rules/shire.md. If the db_path points to a local directory (e.g., .shire/index.db), it offers to add that directory to .gitignore.
Manual setup
If you prefer manual configuration, add to ~/.claude.json (global) or .mcp.json (project-level):
{
"mcpServers": {
"shire": {
"command": "shire",
"args": ["serve"]
}
}
}
To keep the index fresh during a session, add a PostToolUse hook to ~/.claude/settings.json:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write|NotebookEdit|Bash",
"hooks": [{ "type": "command", "command": "shire rebuild --stdin" }]
}
]
}
}
Claude Desktop
Add Shire to your claude_desktop_config.json:
{
"mcpServers": {
"shire": {
"command": "shire",
"args": ["serve", "--db", "/path/to/repo/.shire/index.db"]
}
}
}
Other MCP clients
Shire speaks standard MCP over stdio. Any client that supports MCP can connect:
shire serve --db /path/to/repo/.shire/index.db
Use --root to enable on-demand reindexing. Before answering a query the
server re-checks the working tree — at most once per serve.debounce_s
window (default 5 seconds) — by running an incremental build, so unstaged
edits are picked up without any hook:
shire serve --root /path/to/repo
Editor registration
For editors and CLIs other than Claude Code, shire install registers the built shire
binary as an MCP server with every supported tool it finds on the machine: Claude Code
(via the claude CLI, falling back to file patching), Codex CLI, Cursor, Windsurf,
Gemini CLI, VS Code, and Zed. It writes the current binary’s absolute path (via
std::env::current_exe) rather than a bare shire, so registrations keep working even
if the tool that launches them doesn’t inherit your shell’s PATH.
shire install # register with every detected tool
shire install --dry-run # show what would change without writing anything
shire install --force # overwrite existing registrations (e.g. after moving the binary)
shire uninstall # remove shire's registration from every detected tool
shire uninstall --dry-run
install/uninstall only touch each tool’s own MCP config file (or the tool’s own CLI,
for Claude Code and Codex); they do not create or modify shire.toml, PostToolUse hooks,
or the rules file — use shire init for those.
CLI reference
Build an index
shire build --root /path/to/repo
Rebuild from scratch
Ignore cached hashes and re-parse everything:
shire build --root /path/to/repo --force
Custom database location
shire build --root /path/to/repo --db /tmp/my-index.db
The index defaults to .shire/index.db inside the repo root. Override with --db or db_path in shire.toml (see Configuration).
Clean up
Remove the index database, WAL/SHM files, the .shire directory, and stop the watch daemon:
shire clean
Index status
Show the index’s state without rebuilding or writing anything: whether a build is running,
when the index was built and at which commit (and whether HEAD has moved since), counts,
packages still owed a source re-check, the last build’s failures, whether the file walk saw
the whole tree, and the watch daemon’s liveness:
shire status # human-readable
shire status --json # one JSON object, for scripts and editor integrations
state is one of missing, refused (symlinked db_path), unreadable, building,
interrupted (the last build died part-way; the next build repairs it) or ok. With no
--root, the repo is found by walking up from the current directory. The command always
exits 0, even when shire.toml cannot be read (state is then unreadable, db_path is null and
error says why); read state to decide.
For Claude Code, shire init --mod installs a mod that polls shire status --json and shows
index health in the status line (see Claude Code status mod).
Watch daemon status
Check whether the watch daemon is running for a repo (PID, socket path, and whether it’s actually reachable — see Watch Daemon):
shire watch --root /path/to/repo --status
Incremental builds
Subsequent builds are incremental — only manifests whose content has changed (by SHA-256 hash) are re-parsed. Source files are tracked at per-file granularity: if individual source files change without a manifest change, only those files have their symbols re-extracted. An mtime pre-check skips hash computation entirely for packages whose source files haven’t been touched since the last build.
File indexing is also incremental — a file-tree hash detects structural changes, skipping the file indexing phase entirely when no files have been added, removed, or resized.
Symbol extraction and source hashing are parallelized across packages and within packages using rayon for multi-core throughput. Files are read once per build (single-pass hash + extraction). All database writes use batched multi-row INSERTs within explicit transactions, with FTS5 triggers temporarily disabled during bulk operations for maximum SQLite throughput.
Build progress
shire build shows real-time progress for each build phase:
- Spinners for quick phases (discovering manifests, workspace context, recomputing internals, indexing files)
- Progress bars with ETAs for longer phases (parsing manifests, extracting symbols)
Progress bars persist after completion so you can see the full build history in your terminal. Quiet mode (used internally by the MCP server for on-demand rebuilds) hides all progress output.