Code Intelligence (MCI)

A queryable semantic map of your codebase — every function, class, and route is a symbol; every call, import, and test relationship is an edge. Shared across every agent in your workspace.

What MCI is, in plain English

Your codebase is a graph — every function connects to every function that calls it, every file it imports, every test that covers it. MCI builds and maintains that graph so AI agents (and humans) can answer two questions that normally take an hour:

  1. Where is the thing that does X? — by meaning, not text. Search "user signup flow" and find the right function even when it's named createInitialAccount and never uses the word "signup."
  2. What breaks if I change this? — every caller, every test, every file that historically changes alongside it. Before the edit, not after the bug.

Everything else MCI does (architectural tours, cluster maps, multi-agent coordination) is downstream of that graph. Finding and impact are why it earns its keep.

One-liner: Grep finds strings. MCI finds meaning and consequences.
Endpoint: https://mcp.momentalos.com/mcp/v3. Legacy momental_code_* tool names from v1 still work as translating stubs — see the v1 → v3 mapping for the full table.

The four tools

ToolActionsWhat it answers
code_search find, search, file "Where is X?" — exact lookup, hybrid semantic + BM25, all-symbols-in-file with callers/callees inline
code_inspect symbol, blast, deps, diff_impact, rename_impact, tests, traces "What breaks if I change X?" — 360° symbol view, blast radius, dependency tree, change-impact, rename-impact, test coverage, runtime traces
code_map clusters, map, tour, graph "How is this codebase organised?" — Louvain clusters, Mermaid diagram, persona-tuned tour, raw graph queries
code_manage register, list, clear, delete, check_pending, submit_index, update_files, embed, cochange, references, claim, active, review Repo registration, indexer ingest endpoints, multi-agent file-claim coordination, Vega review hand-off

Full schemas in the MCP Tool Reference (items 27–30).

Graph model

ElementDetail
Symbol id, qualifiedName, name, filePath, startLine, endLine, kind (FUNCTION, CLASS, INTERFACE, TYPE, METHOD, CONSTANT, VARIABLE, EXPORT), signature, docstring, isExported, isEntryPoint
Edge fromQualifiedName, toQualifiedName, edgeType (CALLS, IMPORTS, EXTENDS, IMPLEMENTS, REFERENCES, RE_EXPORTS, TESTS), optional confidence, filePath, callLine
Reference LSP-sourced (TS auto-detected). Enables type refs, generics, decorators, JSX usage in code_inspect blast. Submitted via code_manage action:references.
Co-change pair fileA, fileB, coChangeCount, frequency from git log. Submitted via code_manage action:cochange.
Cluster Louvain community of related symbols, named by an LLM (claude-haiku) on first compute.
Embedding Per-symbol semantic vector. Without embeddings, code_search action:search falls back to BM25 with degraded: true.

Languages with full AST extraction: TypeScript, JavaScript, Python, Go. Swift uses regex-based same-file CALLS only.

The npm package: @momentalos/cli

The indexer and agent listener ship as one published package: @momentalos/cli. Requires Node.js 20+.

npm install -g @momentalos/cli

Or run without installing:

npx -p @momentalos/cli momental-indexer --help
npx -p @momentalos/cli momental-agent   --help

Three bins

BinPurpose
momental CLI router — momental index …, momental agent, momental completion
momental-indexer The MCI indexer — parses your codebase and submits the symbol graph. This is what populates the graph the four code_* tools query.
momental-agent The agent listener daemon — outbound WSS to the Momental relay; spawns Claude Code when tasks are assigned to your agent. No inbound ports required.

Environment variables

VariableDefaultPurpose
MOMENTAL_API_KEYAPI key (mmt_*); alternative to --api-key
MOMENTAL_MCP_URLhttps://mcp.momentalos.com/mcp/v3MCP endpoint override
MOMENTAL_AGENT_IDAgent ID for coding-tool keys (find in .mcp.json)

API key auto-discovery (first hit wins): --api-key flag → $MOMENTAL_API_KEY.mcp.json walked up to home → ~/.claude.json~/.momental/config.json.

Indexing — full vs. incremental

Indexing populates the graph for one repo. There are two paths:

First-time full index

momental-indexer \
  --dir . \
  --api-key mmt_YOUR_KEY \
  --name my-repo \
  --ts-calls \
  --ts-tests \
  --git-cochange \
  --git-sha "$(git rev-parse HEAD)"

Pipeline:

  1. Calls code_manage action:register (or reuses --repo-id) → returns repoId.
  2. Walks the source tree, respecting .gitignore and --exclude.
  3. Extracts symbols via AST (TypeScript Compiler API, python3 AST, go compiler, Swift parser); falls back to enhanced regex if a runtime is missing.
  4. Builds edges: IMPORTS, EXTENDS, IMPLEMENTS, plus type-aware CALLS when --ts-calls.
  5. Optional: TESTS edges (--ts-tests), DI edges (--ts-di), git co-change pairs (--git-cochange), LSP references (auto-detected for TS).
  6. Submits via code_manage action:submit_index — atomic full replacement.
  7. Follow-ups: submit_references if LSP refs were extracted; cochange if --git-cochange ran.

After the full index lands, kick off semantic embeddings asynchronously:

# via MCP — generates embeddings for all symbols missing them
code_manage({ action: "embed", repoId })

Embedding takes ~1 minute per ~1k symbols. Until embeddings exist, code_search action:search returns degraded: true and ranks via BM25 alone.

Incremental reindex on top of an existing index

Use this after editing files — much faster than a full re-index, and preserves co-change pairs and embeddings for files you did not touch.

Stdin file list (typical CI / git-hook):

git diff --name-only HEAD~1 HEAD | \
  momental-indexer \
    --dir . \
    --repo-id <existing-repo-id> \
    --incremental-files - \
    --git-sha "$(git rev-parse HEAD)"

Explicit file list:

momental-indexer \
  --dir . \
  --repo-id <existing-repo-id> \
  --incremental-files src/auth.ts,src/billing.ts

Behind the scenes the indexer:

  1. Parses only the listed files.
  2. Calls code_manage action:update_files with { repoId, filePaths, symbols, edges }.
  3. The handler deletes stale symbols for those files, then inserts the new ones.
  4. Co-change pairs, embeddings, and references for unchanged files are untouched.

update_files is the canonical "incremental on top of existing index" entry point. submit_index, by contrast, is always a full wipe-and-replace for the repo.

Pending-reindex signal (UI-triggered reindex)

When a user clicks "Reindex" in the Momental UI (or another process wants the indexer to re-run), the request is recorded as a pending reindex on the repo row. An indexer running in --watch mode polls for those requests and runs a full index when one appears:

momental-indexer \
  --dir . \
  --repo-id <existing-repo-id> \
  --watch 30   # poll interval in seconds

Programmatic check:

code_manage({ action: "check_pending" })
# → repos where reindexRequestedAt > lastIndexedAt

--watch requires --repo-id (the watched repo). Use this on a long-running developer machine or a CI box to keep one repo continuously up to date with UI-triggered requests.

CI integration (GitHub Actions)

Full index on main:

- name: Index codebase
  run: |
    npm install -g @momentalos/cli
    momental-indexer \
      --dir . \
      --api-key "${{ secrets.MOMENTAL_API_KEY }}" \
      --name my-repo \
      --ts-calls --ts-tests --git-cochange \
      --git-sha "$(git rev-parse HEAD)"

Incremental on PR (only changed files):

- name: Incremental MCI update
  run: |
    git diff --name-only origin/main...HEAD | \
      momental-indexer \
        --dir . \
        --repo-id "${{ secrets.MOMENTAL_REPO_ID }}" \
        --incremental-files - \
        --git-sha "$(git rev-parse HEAD)" \
        --quiet

Most-used indexer flags

FlagMeaning
--dir <path>Root directory to index (default: cwd)
--api-key <key>API key (mmt_*); or set MOMENTAL_API_KEY
--name <name>Repo display name in Momental (default: directory name)
--repo-id <id>Existing repo ID — skips registration; required for incremental and --watch
--lang <lang>typescript (default), javascript, python, go, swift
--ts-callsType-aware CALLS via TS compiler API (recommended; auto-detected with tsconfig.json)
--ts-testsTESTS edges from test files → source files (auto-enabled)
--ts-diNestJS / Angular constructor injection CALLS (auto-detected)
--git-cochangeParse git log for files-that-change-together pairs
--cochange-limit NMax commits scanned for co-change (default 500)
--git-sha <sha>Record current commit SHA in repo metadata
--incremental-files -|<list>Reindex only listed files (stdin or comma-separated list)
--watch <seconds>Poll for UI-triggered reindex requests; runs full index when one appears
--exclude <paths>Comma-separated dirs to skip relative to --dir
--dry-runParse only — no submission
--quiet / -qSuppress non-error output
--versionPrint indexer version and exit

Daily usage — the agent playbook

For agents and humans both, MCI replaces grep / glob / cold reads. The mandate inside Momental's own agents:

Before touching any file — search MCI first.
Before modifying any function — check its blast radius first.
Before writing any code — claim your files first.

Recommended startup sequence (every session)

1. code_manage({ action: "list" })                              # what repos are indexed
2. code_map({ action: "tour", repoId, persona: "agent" })       # for new codebases — dependency-ordered learning path
3. code_manage({ action: "claim", repoId, filePaths, taskId })  # before edits
4. code_inspect({ action: "diff_impact", repoId, filePaths })   # blast + testsToRun[] before writing
5.   ... do the work ...
6. code_inspect({ action: "tests", repoId, filePath })          # exactly the right tests, not all tests

Don't do these without MCI first

Banned shortcutMCI alternative
grep -r "functionName" code_search({ action: "find", name: "functionName" })
grep -r "concept" code_search({ action: "search", query: "concept" })
cat src/service.ts (cold) code_search({ action: "file", repoId, filePath }) — callers/callees inline
Editing without context code_inspect({ action: "blast", symbolIds }) first
Starting any edit code_manage({ action: "claim", repoId, filePaths, taskId }) first

grep misses callers in other files. A change that looks local often has 10 upstream callers you'll never find without MCI.

Multi-agent coordination

code_manage action:claim is advisory, not a hard lock. TTL is 600 s by default; refresh with another claim call every ~480 s on long sessions. Conflicts are returned as warnings (with the colliding agent's id), not hard errors. Pass force: true to proceed despite a conflict (after coordinating via the Agent Room or task comments).

See live claims:

code_manage({ action: "active", repoId })
# → { activeAgents: 3, claims: [{ agentId, filePaths, ttlRemainingSeconds, isExpired }] }

Architecture notes & non-obvious behavior

AspectBehavior
Search ranking code_search action:search is hybrid: BM25 + cosine over embeddings, normalised to [0, 1]. Relevance labels: HIGH ≥ 0.7, MEDIUM ≥ 0.4, LOW < 0.4.
Degraded mode If a repo has no embeddings, the result includes degraded: true and BM25-only results are served. Run code_manage action:embed to enable semantic ranking.
Blast radius depth Default maxDepth: 5, max 8. isPartialResult: true indicates at least one node was reached at maxDepth — paths beyond that are truncated.
Risk levels code_inspect blast returns riskLevel: P0…P5 | UNKNOWN. UNKNOWN means the graph has no CALLS edges to walk (typical of repos indexed without --ts-calls).
Cluster naming Louvain community detection; cluster names are LLM-generated (claude-haiku) on recompute: true. Cost ≈ $0.001 per cluster. Falls back to directory-derived names if the LLM is unavailable.
Path normalisation code_inspect diff_impact accepts package-relative, src-relative, or git-root-relative paths and normalises to the indexer's storage form.
Module-import edges code_inspect symbol flags file-level imports with isModuleImport: true — render as "imported by" rather than "called by".
Test detection code_inspect tests requires the indexer ran with --ts-tests (auto-enabled in current versions). Returns runCommand like pnpm test <first-test-file>.
Idempotent register code_manage register upserts on (teamId, lower(trim(repoUrl ?? name))) — no duplicate rows on re-run.
Privacy The indexer transmits only symbol names, signatures truncated at the first {, docstrings, and line numbers. No source code is sent.

Troubleshooting

SymptomLikely cause / fix
code_search action:search returns degraded: true No embeddings yet — call code_manage action:embed, wait ~1 min per 1k symbols.
code_inspect action:blast returns riskLevel: UNKNOWN Repo was indexed without --ts-calls. Re-run the indexer with --ts-calls.
code_inspect action:tests returns no tests Indexer didn't emit TESTS edges. Re-index with --ts-tests (auto-enabled in v3.x indexer).
Python / Go / Swift symbols present, edges very sparse Install python3 / go for AST-based extraction. Swift cross-file CALLS are not supported.
momental-indexer: No Momental API key found Pass --api-key mmt_…, set $MOMENTAL_API_KEY, or place the key in .mcp.json / ~/.claude.json / ~/.momental/config.json.
Cluster names look like file paths LLM was unavailable when clusters were last computed — re-run with code_map({ action: "clusters", repoId, recompute: true }).
Claim conflicts on long-running edit Refresh the claim every ~480 s with another code_manage action:claim call (TTL is 600 s).
Reindex never picks up new commits Either run momental-indexer (incremental or full), or run it with --watch <seconds> so UI-triggered check_pending requests fire automatically.
Install the indexer
npm install -g @momentalos/cli
First full index
momental-indexer \
  --dir . \
  --api-key mmt_YOUR_KEY \
  --name my-repo \
  --ts-calls --ts-tests \
  --git-cochange
Incremental reindex
git diff --name-only HEAD~1 | \
  momental-indexer \
    --repo-id <id> \
    --incremental-files -
Find webhook auth
code_search({
  action: "search",
  query: "webhook authentication"
})
Blast radius of a PR
code_inspect({
  action: "diff_impact",
  repoId,
  filePaths: [
    "src/routes/payments.ts",
    "src/services/billing.ts"
  ]
})
Claim before editing
code_manage({
  action: "claim",
  repoId,
  filePaths: ["src/auth.ts"],
  taskId
})