Getting started
Five steps: install the toolchain, build the daemon, launch the TUI, index a repo, and ask your first grounded question. Everything runs locally.
1 · Prerequisites
| Requirement | Why | Check |
|---|---|---|
| Node.js 20+ | runtime. Native modules build against Node 22.22.1 headers; the daemon spawns under Node 22 at install. | node -v |
| Ollama | local LLM + embeddings — embeddings are local-only, so this is always required. | ollama --version |
| claude and/or codex CLI | cloud LLM access is delegated to these CLIs' OAuth sessions — insrc never makes direct REST calls. | claude --version |
| git | repo discovery, the git tools, and the workflow tracker. | git --version |
$ ollama pull qwen3.6:35b-a3b # analyzer / shaper core model
$ ollama pull qwen3-embedding:0.6b # embeddings — 1024-dim, local-only
Embeddings are always local. The analyzer model is only needed when shaperProvider is ollama — skip qwen3.6:35b-a3b if you drive analyze / workflow reasoning through the claude / codex CLI instead.
2 · Install
A · Release installer (recommended)
Download insrc-daemon-install.sh from the latest release and run it. The
script is the entire distribution — it verifies prerequisites, clones + builds the daemon
into ~/.insrc/daemon, and starts it. Update later by re-running it or with
~/.insrc/daemon/scripts/daemon-ctl.sh update.
$ ./insrc-daemon-install.sh # clones + builds into ~/.insrc/daemon, then starts it
# options: --target <path> --branch main --no-start --repo <fork-url> --embedder auto|ollama|onnx
B · From source (development)
For working on the daemon itself:
$ git clone https://github.com/insors-ai/insrc.git
$ cd insrc
$ npm install # runtime + dev deps (builds native modules)
$ npm run build # tsc + copy-assets.mjs → out/
The two entry points produced by the build:
out/daemon/index.js— the daemon binary the IDE spawns.out/bin/insrc-mcp.js— the MCP binary you register withclaude/codex.
$ npx tsx --test 'src/workflow/**/*.test.ts' 'src/mcp/**/*.test.ts' # ~5s
$ npx tsx --test 'src/**/__tests__/*.test.ts' # full sweep
INSRC_LIVE_TESTS=1 and skip cleanly when unset.
3 · Launch the TUI
The insrc command is a full-screen ink (React) TUI. It starts (or attaches to) the daemon and gives you Daemon / Repos / Workflows / Setup panes.
$ npx insrc
┌─ Repos ───────────────────────────────────────────┐
│ ● insrc ready · 3,412 entities │
│ ○ my-service indexing · 61% │
└───────────────────────────────────────────────────┘
a add repo r re-index d remove ↑↓ select
4 · Add & index a repo
Registry membership is established exclusively through the repo.add IPC — from the TUI, open the Repos pane and press a. The daemon parses the tree with tree-sitter, builds the graph, and generates embeddings.
During a, insrc asks — per file — whether to install the steering block into the repo's CLAUDE.md (Claude Code) and/or AGENTS.md (Codex). Say yes and the daemon writes a safe, idempotent insrc:steering marked section (created if absent, replaced in place on re-add, never clobbering your surrounding content) so a controller reaches for insrc_analyze_step on code questions, insrc_triage first on build requests, and insrc_review_step before approving. No manual copy-paste needed.
From the command bar (non-interactive, so it can't prompt) pass the flag explicitly: repo add <path> --steering installs both, or --steering=claude / --steering=agents for one. Bare repo add <path> installs nothing (no silent write) and prints a reminder.
UnregisteredRepoError — the storage layer never auto-allocates registry rows. Always add a repo before expecting queries to resolve.Wait for the status to reach ready (embeddings pending shows as a count). Graph searches span the transitive DEPENDS_ON closure of the active repo, so add dependency repos too if you want cross-repo answers.
On add, insrc writes a per-repo .insrc/config.json with an ignore section — seeded from the repo's .gitignore when present, otherwise from its type (node / python / java / go). Edit it to control which directories the indexer and file-watcher skip (e.g. node_modules, dist, target, __pycache__). It's created idempotently and never overwritten once you've customised it.
5 · Ask your first question
For any question about a codebase's structure, conventions or capabilities, use the analyze tools — every claim is grounded in a real graph exploration, with file paths drawn from the index (no hallucinated paths).
$ insrc analyze "list the storage layers and where each is initialised"
Prefer insrc_analyze_step (multi-turn, stays in your session) over the one-shot insrc_analyze when driving from an MCP client — it's more accurate and doesn't spawn a separate billing path. See the analyze guide.
Register the MCP servers
To let claude / codex call insrc directly, register the MCP binary insrc-mcp.js with each client. It exposes the full tool suite — insrc_analyze_step, insrc_triage, insrc_workflow_step / insrc_workflow_run, insrc_review_step and insrc_build_step. The installer puts the binary at ~/.insrc/daemon/out/bin/insrc-mcp.js; a from-source build has it at out/bin/insrc-mcp.js in the repo.
INSRC_REPO pin. A project-scoped registration (Claude's .mcp.json) exposes insrc only inside that one repo, so a session in any other repo won't see the tools at all — the usual cause of "insrc isn't being used here."Claude Code
Register at user scope so insrc is available in every repo:
$ claude mcp add insrc --scope user -- node ~/.insrc/daemon/out/bin/insrc-mcp.js
$ claude mcp list # insrc: … ✔ Connected
To scope it to a single repo instead, drop a .mcp.json at that repo's root — insrc is then visible only inside it. Use an absolute path (~ is not expanded in JSON):
{
"mcpServers": {
"insrc": {
"command": "node",
"args": ["/Users/you/.insrc/daemon/out/bin/insrc-mcp.js"]
}
}
}
Codex
Codex servers in ~/.codex/config.toml are global by nature — add the insrc server there (absolute path; no ~):
[mcp_servers.insrc]
command = "node"
args = ["/Users/you/.insrc/daemon/out/bin/insrc-mcp.js"]
Restart the client (or reconnect its MCP) after editing a config file — both read it at startup.
How the repo is resolved
Resolution is session-aware for both clients, in order: an explicit repo argument wins; otherwise the server matches its working directory against the registered repos (the session workspace — both clients spawn the server with the workspace as its CWD); otherwise it falls back to an optional INSRC_REPO env for headless / cron use where there's no meaningful working directory. That's why one global registration with no INSRC_REPO works everywhere. Either way the repo must be registered with the daemon and finished indexing.