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

RequirementWhyCheck
Node.js 20+runtime. Native modules build against Node 22.22.1 headers; the daemon spawns under Node 22 at install.node -v
Ollamalocal LLM + embeddings — embeddings are local-only, so this is always required.ollama --version
claude and/or codex CLIcloud LLM access is delegated to these CLIs' OAuth sessions — insrc never makes direct REST calls.claude --version
gitrepo discovery, the git tools, and the workflow tracker.git --version
Pull the two local models — the analyzer core and the embedder:
bash
$ 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.

bash
$ ./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:

bash
$ 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:

Sanity-check the build with the fast test subsets:
bash
$ npx tsx --test 'src/workflow/**/*.test.ts' 'src/mcp/**/*.test.ts'   # ~5s
$ npx tsx --test 'src/**/__tests__/*.test.ts'                       # full sweep
Live-service suites gate behind 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.

bash
$ npx insrc
insrc — Repos
┌─ 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.

The repo registry is the contract. An entity whose repo path isn't registered fails the upsert with 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).

bash
$ 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.

Register once, at user / global scope. Repo resolution is session-aware, so a single global registration serves every repo and every concurrent session — no per-repo config, no 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:

bash
$ 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):

<repo>/.mcp.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 ~):

~/.codex/config.toml
[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.

Where next