symforge 6.0.1

SymForge — in-memory code intelligence MCP server for Claude Code, Codex, and Gemini CLI
Documentation

SymForge

A code-native MCP server that gives AI coding agents structured, symbol-aware access to codebases. Built in Rust with tree-sitter, it replaces raw file scanning with tools that understand code as symbols, references, dependency graphs, and git history through a single MCP connection.

Works with MCP-compatible clients including Claude Code, Codex, Gemini CLI, VS Code MCP, Kilo Code, Roo Code, Cline, Continue, JetBrains plugins, and custom agents.

[!IMPORTANT] Rust-native31 tools19 source languages5 config formats6 promptsBuilt-in resources

Use SymForge first for source-code reads, search, repo orientation, symbol tracing, and structural edits. Use raw file reads for docs and config when exact wording is the point. Use shell tools for builds, tests, package managers, Docker, and general system tasks. Kilo Code is workspace-local and should be initialized from the target project directory.

When to use SymForge

Use SymForge when an agent needs to:

  • understand a repo without reading large files blindly
  • find symbols, call sites, dependencies, and changed code
  • edit code structurally by symbol instead of by raw text
  • reindex and inspect impact after edits

Do not expect SymForge to replace normal shell workflows for process execution, runtime debugging, package management, or OS-level tasks.

Install

Prerequisite: Node.js 18+

Prebuilt binaries: Windows x64, Linux x64, macOS arm64, macOS x64

npm install -g symforge

This installs the npm wrapper and downloads the platform binary to ~/.symforge/bin/symforge (or symforge.exe on Windows). Set SYMFORGE_HOME to override the default home directory.

Auto-configured clients

During global install, SymForge auto-configures these home-scoped clients if their home directories already exist:

  • Claude Code
  • Codex
  • Gemini CLI

Kilo Code is different:

symforge init --client kilo-code

Run that from the target project directory. It writes .kilocode/mcp.json, .kilocode/rules/symforge.md, and .symforge/ in that workspace.

Re-run setup manually

symforge init
symforge init --client claude
symforge init --client codex
symforge init --client gemini
symforge init --client kilo-code
symforge init --client all

After setup, confirm in your client that the SymForge MCP server is connected or ready.

Core workflows

Goal Use these tools first
Start in a repo health, get_repo_map, explore
Read code get_file_context, get_symbol, get_symbol_context
Exact raw read get_file_content
Find code search_symbols, search_text, search_files
Trace impact find_references, find_dependents, what_changed, diff_symbols
Edit code edit_plan, replace_symbol_body, edit_within_symbol, insert_symbol, delete_symbol, batch_edit, batch_rename, batch_insert
Refresh index after edits analyze_file_impact, index_folder
Validate configs validate_file_syntax
Ask in plain English ask

Practical defaults:

  • call get_file_context before reading a source file
  • use search_text or search_symbols before broad grep or raw file scans
  • use get_file_content when exact docs/config text matters
  • run analyze_file_impact after small edits and index_folder after larger multi-file work
  • edit_plan accepts a bare symbol, a file path, or path::symbol; batch_edit and batch_insert also accept shorthand strings like src/lib.rs::helper => delete and src/lib.rs::helper

Need deeper reference?

The README is intentionally action-first. For deeper reference material, use the wiki:

[!IMPORTANT] NOTICE — One prompt for any AI agent after SymForge install

If your AI agent still falls back to built-in file reads, grep, or text-based edits after SymForge is installed, give it the following prompt once. It is written to work whether the machine has one client or several.

SymForge is already installed on this machine. Your job is to detect which supported AI clients are actually installed on this computer or in this workspace, configure SymForge for the ones you find, and update only the relevant instruction files. Do not assume every client is installed. Do not split this into multiple partial tasks. Complete the whole setup flow for every detected client.

Work in this order:
1. Detect installed clients and existing config files before editing anything.
2. Prefer running `symforge init` for any client that supports it.
3. Repair or add the SymForge MCP entry in that client's MCP config only if needed.
4. Update the corresponding global or workspace instruction file so the agent treats SymForge as the primary code navigation and structural editing layer.
5. Validate the edited config, reload the client if needed, and confirm that SymForge is connected or ready.

Requirements:
- First inspect what exists. Only modify files for clients you actually detect.
- Preserve existing user instructions and existing MCP servers. Merge missing SymForge settings; do not duplicate entries or overwrite unrelated content.
- Use the SymForge binary path for the current OS: `~/.symforge/bin/symforge` on macOS/Linux or `C:\Users\<user>\.symforge\bin\symforge.exe` on Windows. Use no arguments unless that client already requires extra fields.
- For JSON-based MCP clients, keep the client's existing schema. Native VS Code MCP uses a top-level `servers` object in `mcp.json`. Many extension-managed clients use a top-level `mcpServers` object. Reuse the schema already present in that client's config file instead of forcing one client's format into another.
- Preserve client-specific keys such as `disabled`, `alwaysAllow`, `autoApprove`, `timeout`, `type`, `env`, or trust fields if that client supports them. Do not invent unsupported keys.
- If a SymForge entry already exists, update it in place. Do not create duplicate `symforge` entries.
- After editing any JSON config, validate that it is still valid JSON and confirm the client can start the SymForge MCP server.
- If a client reports MCP schema errors that mention another tool or server, do not blame SymForge by default. Check the other configured MCP servers in that client, because many strict clients reject the whole MCP set when any one server advertises invalid JSON Schema.

Detect and update whichever of these are actually present:
- Claude Code: `~/.claude.json`, `~/.claude/settings.json`, `~/.claude/CLAUDE.md`
- Codex: `~/.codex/config.toml`, `~/.codex/AGENTS.md`
- Gemini CLI: `~/.gemini/settings.json`, `~/.gemini/GEMINI.md`
- Native VS Code MCP: workspace or user `mcp.json` and the nearest project instruction file such as `AGENTS.md`
- Cline: its MCP JSON settings file plus its rules file such as `~/Documents/Cline/Rules/mandatory.md`
- Kilo Code: `.kilocode/mcp.json` and `.kilocode/rules/symforge.md`
- Roo Code and similar extensions: their existing MCP JSON file if present, otherwise the nearest MCP config file the extension already uses, plus the nearest project instruction file the client already consumes
- If a client is not installed or you cannot find its real config path from existing files, do not guess and do not create random paths for it

Client-specific setup notes:
- Claude Code, Codex, and Gemini CLI are home-scoped clients. If their home directories already exist, prefer `symforge init` and then verify the written config instead of hand-authoring everything from scratch.
- Kilo Code is workspace-local. Run `symforge init --client kilo-code` from the target project directory when possible. That workspace should end up with `.kilocode/mcp.json`, `.kilocode/rules/symforge.md`, and `.symforge/`.
- Native VS Code MCP usually uses user- or workspace-level `mcp.json`. Keep its top-level `servers` shape intact.
- Cline, Roo Code, Kilo Code, and similar VS Code extensions may use extension-managed JSON files instead of native VS Code `mcp.json`. Detect the real file first and preserve its root key and surrounding schema.
- For VS Code-family extensions, update both sides when appropriate: the MCP JSON file that launches SymForge and the instruction/rules file the extension already consumes.

Add or merge a SymForge rule block with this behavior:
- When SymForge is available, prefer it over built-in file, search, and edit tools for source code work.
- Use SymForge first for: `search_symbols`, `search_text`, `get_file_context`, `get_repo_map`, `get_symbol`, `get_symbol_context`, `find_references`, `find_dependents`, `inspect_match`, `what_changed`, `diff_symbols`, `explore`, `ask`, `conventions`, `edit_plan`, `context_inventory`, `investigation_suggest`.
- Prefer SymForge edit tools: `replace_symbol_body`, `edit_within_symbol`, `insert_symbol`, `delete_symbol`, `batch_edit`, `batch_rename`, `batch_insert`.
- Do not default to built-in tools such as `read_file`, `search_files`, `list_files`, `write_to_file`, `replace_in_file`, grep, or broad raw file reads for normal source-code work.
- Raw reads are still acceptable for non-code files where exact wording matters, such as docs and config files.
- If SymForge reports that the project is empty, missing, stale, loading, degraded, or otherwise unavailable, do not give up on SymForge. Run `health`, then run `index_folder` on the workspace root if needed, then retry the original SymForge operation.
- Only fall back to built-in code tools after SymForge recovery was attempted and still failed for a non-indexing reason.
- After small edits, run `analyze_file_impact` on changed files.
- After larger multi-file jobs, major refactors, or sprint-sized tasks, run `index_folder` on the workspace root so the index is fresh.
- Before finishing a large task, do a final `health` check and reindex if needed.

Your output must include:
- which clients you detected
- which files you changed
- which files you intentionally left untouched because the client was not installed or no real config file was found
- the SymForge rule block you added or updated
- confirmation that each edited MCP config still parses and points to the SymForge binary

Operational notes

  • symforge daemon is optional if you want a shared index across multiple terminal sessions.
  • Index snapshots persist at .symforge/index.bin for fast restarts.
  • Use get_file_content for literal document and config reads.
  • Use validate_file_syntax when a config file may be malformed.

Environment variables

Variable Default Effect
SYMFORGE_HOME ~/.symforge Home directory for the binary and daemon metadata
SYMFORGE_AUTO_INDEX true Enables project discovery and startup indexing
SYMFORGE_HOOK_VERBOSE unset Set to 1 for stderr hook diagnostics
SYMFORGE_CB_THRESHOLD 0.20 Parse-failure circuit-breaker threshold
SYMFORGE_RECONCILE_INTERVAL 30 Watcher reconciliation interval in seconds; set to 0 to disable periodic reconciliation sweeps
SYMFORGE_SIDECAR_BIND 127.0.0.1 Sidecar bind host for local in-process mode
SYMFORGE_DAEMON_BIND loopback bind host Overrides the daemon bind host used for the shared local daemon

[!NOTE] Run This In Your Terminal

These commands establish a recommended baseline for normal SymForge behavior. They are useful if you want your shell or user profile to hold explicit SymForge defaults instead of relying on implicit defaults.

[!TIP] Recommended baseline

  • keep startup indexing enabled with SYMFORGE_AUTO_INDEX=true
  • keep hook diagnostics off by default by leaving SYMFORGE_HOOK_VERBOSE unset
  • keep the standard watcher reconciliation interval with SYMFORGE_RECONCILE_INTERVAL=30
  • keep loopback bind hosts for SYMFORGE_SIDECAR_BIND and SYMFORGE_DAEMON_BIND
  • keep the standard circuit-breaker threshold with SYMFORGE_CB_THRESHOLD=0.20

[!WARNING] Copy carefully

The examples below set a recommended baseline, not a debug profile. The persistent examples are written to be idempotent: re-running them updates the same variables instead of appending duplicate config blocks.

PowerShell

Current terminal session only:

$env:SYMFORGE_HOME = "$HOME\\.symforge"
$env:SYMFORGE_AUTO_INDEX = "true"
Remove-Item Env:SYMFORGE_HOOK_VERBOSE -ErrorAction SilentlyContinue
$env:SYMFORGE_CB_THRESHOLD = "0.20"
$env:SYMFORGE_RECONCILE_INTERVAL = "30"
$env:SYMFORGE_SIDECAR_BIND = "127.0.0.1"
$env:SYMFORGE_DAEMON_BIND = "127.0.0.1"

Persist for the current Windows user:

[Environment]::SetEnvironmentVariable("SYMFORGE_HOME", "$HOME\\.symforge", "User")
[Environment]::SetEnvironmentVariable("SYMFORGE_AUTO_INDEX", "true", "User")
[Environment]::SetEnvironmentVariable("SYMFORGE_HOOK_VERBOSE", $null, "User")
[Environment]::SetEnvironmentVariable("SYMFORGE_CB_THRESHOLD", "0.20", "User")
[Environment]::SetEnvironmentVariable("SYMFORGE_RECONCILE_INTERVAL", "30", "User")
[Environment]::SetEnvironmentVariable("SYMFORGE_SIDECAR_BIND", "127.0.0.1", "User")
[Environment]::SetEnvironmentVariable("SYMFORGE_DAEMON_BIND", "127.0.0.1", "User")

These calls overwrite the same user-level variable names, so re-running them is already idempotent.

CMD

Current terminal session only:

set SYMFORGE_HOME=%USERPROFILE%\.symforge
set SYMFORGE_AUTO_INDEX=true
set SYMFORGE_HOOK_VERBOSE=
set SYMFORGE_CB_THRESHOLD=0.20
set SYMFORGE_RECONCILE_INTERVAL=30
set SYMFORGE_SIDECAR_BIND=127.0.0.1
set SYMFORGE_DAEMON_BIND=127.0.0.1

Persist for the current Windows user:

setx SYMFORGE_HOME "%USERPROFILE%\.symforge"
setx SYMFORGE_AUTO_INDEX "true"
setx SYMFORGE_HOOK_VERBOSE ""
setx SYMFORGE_CB_THRESHOLD "0.20"
setx SYMFORGE_RECONCILE_INTERVAL "30"
setx SYMFORGE_SIDECAR_BIND "127.0.0.1"
setx SYMFORGE_DAEMON_BIND "127.0.0.1"

setx updates the same variable names instead of creating duplicates. Open a new terminal after running it.

Linux Terminal

Current shell session only:

export SYMFORGE_HOME="$HOME/.symforge"
export SYMFORGE_AUTO_INDEX=true
unset SYMFORGE_HOOK_VERBOSE
export SYMFORGE_CB_THRESHOLD=0.20
export SYMFORGE_RECONCILE_INTERVAL=30
export SYMFORGE_SIDECAR_BIND=127.0.0.1
export SYMFORGE_DAEMON_BIND=127.0.0.1

Persist for future shells:

export SYMFORGE_RC_FILE="$HOME/.bashrc"
python3 - <<'PY'
from pathlib import Path
import os, re

path = Path(os.environ["SYMFORGE_RC_FILE"]).expanduser()
start = "# >>> SymForge env >>>"
end = "# <<< SymForge env <<<"
block = """# >>> SymForge env >>>
export SYMFORGE_HOME="$HOME/.symforge"
export SYMFORGE_AUTO_INDEX=true
export SYMFORGE_CB_THRESHOLD=0.20
export SYMFORGE_RECONCILE_INTERVAL=30
export SYMFORGE_SIDECAR_BIND=127.0.0.1
export SYMFORGE_DAEMON_BIND=127.0.0.1
# <<< SymForge env <<<"""

text = path.read_text() if path.exists() else ""
pattern = re.compile(re.escape(start) + r".*?" + re.escape(end), re.S)
if pattern.search(text):
    text = pattern.sub(block, text)
else:
    if text and not text.endswith("\n"):
        text += "\n"
    text += block + "\n"
path.write_text(text)
PY
unset SYMFORGE_RC_FILE

source ~/.bashrc

If you use zsh, put the same lines in ~/.zshrc instead.

macOS Terminal

Current shell session only:

export SYMFORGE_HOME="$HOME/.symforge"
export SYMFORGE_AUTO_INDEX=true
unset SYMFORGE_HOOK_VERBOSE
export SYMFORGE_CB_THRESHOLD=0.20
export SYMFORGE_RECONCILE_INTERVAL=30
export SYMFORGE_SIDECAR_BIND=127.0.0.1
export SYMFORGE_DAEMON_BIND=127.0.0.1

Persist for future shells:

export SYMFORGE_RC_FILE="$HOME/.zshrc"
python3 - <<'PY'
from pathlib import Path
import os, re

path = Path(os.environ["SYMFORGE_RC_FILE"]).expanduser()
start = "# >>> SymForge env >>>"
end = "# <<< SymForge env <<<"
block = """# >>> SymForge env >>>
export SYMFORGE_HOME="$HOME/.symforge"
export SYMFORGE_AUTO_INDEX=true
export SYMFORGE_CB_THRESHOLD=0.20
export SYMFORGE_RECONCILE_INTERVAL=30
export SYMFORGE_SIDECAR_BIND=127.0.0.1
export SYMFORGE_DAEMON_BIND=127.0.0.1
# <<< SymForge env <<<"""

text = path.read_text() if path.exists() else ""
pattern = re.compile(re.escape(start) + r".*?" + re.escape(end), re.S)
if pattern.search(text):
    text = pattern.sub(block, text)
else:
    if text and not text.endswith("\n"):
        text += "\n"
    text += block + "\n"
path.write_text(text)
PY
unset SYMFORGE_RC_FILE

source ~/.zshrc

If you use bash on macOS, put the same lines in ~/.bash_profile or ~/.bashrc.

Build from source

cargo build --release
cargo test

The Cargo package name is symforge.

License

SymForge is licensed under PolyForm Noncommercial License 1.0.0. The official license text is also available from the PolyForm Project.

You may inspect, study, and use the source code for noncommercial purposes, but commercial use is prohibited unless separately licensed.