SDK / infra · #81 trending MCP repo

Jcodemunch MCP

jgravelle/jcodemunch-mcp

Symbol-level code retrieval for AI agents: fetch the function you need, not the whole file. Runs locally. 94.5% fewer tokens per lookup on average than grep-and-read on our 15-lookup benchmark. Works with Claude Code, Cursor, Codex and any MCP client. Free for non-commercial use; commercial use needs a one-time license.

Stars
2.8k
This week
—
Forks
373
Open issues
4
Skills inside
11

Inside this repo

11 skills

benchmark-methodologyRules for measuring or quoting any benchmark number in this repo. Load before running the bench tier, writing a delta into a PR or CHANGELOG, or touching anything under benchmarks/..claude/skills/benchmark-methodologychangelog-formatThe shape of a CHANGELOG.md entry and heading in this repo. Load before writing an [Unreleased] line or cutting a release block..claude/skills/changelog-formatclaude-md-budgetHow to keep CLAUDE.md under its character Floor without deleting a rule: measure sections first, rotate by derivability, two edits per rotation. Load in /release step 6 and before any CLAUDE.md rotation or split..claude/skills/claude-md-budgetmechanism-not-instanceThe two questions that separate a fix for the reported spelling from a fix for the property. Load in /fix-issue steps 4-5 and in review of any fix..claude/skills/mechanism-not-instanceobservatoryContext for the jcodemunch-observatory weekly scorecard — what it tracks, the Monday 06:00 UTC cron, why scores must be pulled live rather than transcribed, the NestJS grade story, and the workflow's version dispatch input. Load before quoting, interpreting, or editing observatory scores or config..claude/skills/observatorypr-descriptionThe PR title and body template, and the rules for any comment drafted for a reporter or contributor. Load when writing a PR body, a release PR, or a triage response..claude/skills/pr-descriptionreleasePublishing a jMunch release (jcodemunch-mcp, jdocmunch-mcp, jdatamunch-mcp, jragmunch-cli), reviewing/merging/closing PRs, and responding to the community. Load before any version bump, PyPI upload, tag, GitHub release, MCP registry publish, or PR merge..claude/skills/releasestandard-axesThe criterion numbers of STANDARD.md, so an acceptance criterion can be mapped to one. Load in /feature step 2..claude/skills/standard-axestool-surface-disciplineThe small-front-door principle and what counts as a tool-surface change. Load in /feature step 3, in review, and before editing any tool name, argument, description or tier..claude/skills/tool-surface-disciplineversion-schemeHow the next version number is derived and what a bump touches. Load in /release step 2 or before any version edit..claude/skills/version-schemejcodemunchWhen to use jCodemunch MCP tools for symbol-level code navigation and when the built-in tools are the cheaper route. Loads on demand; complements the always-on policy block.plugin/jcodemunch/skills/jcodemunch

Documentation

README

View on GitHub ↗

jCodeMunch MCP

An MCP server that retrieves source code by symbol, not by file, using tree-sitter AST parsing. It uses 94.5% fewer tokens per lookup on average than grep-and-read on our 15-lookup benchmark (86.9% to 98.7% across the lookups, at pinned commits), so your agent stops spending its context window on whole files.

Benchmark: 5 queries on each of express, fastapi and gin at pinned commits, tokens counted with tiktoken cl100k_base, jcodemunch-mcp at commit 15afcf75, whose version string is 1.108.391 but which also carries the settings-file ranking change released in 1.108.392 and the field/constant change released after it. A lookup is one search_symbols plus get_symbol_source on its top 3 hits, against grep-and-read (rank files by match count, read the top 3 whole). Per lookup, not per session. Reproduce with benchmarks/REPRODUCING.md.

Real results from production, as of 2026-08-17 838B+ tokens saved · 136,000+ reporting installs · $4.2M+ in AI spend avoided · 100,000+ kg CO₂ prevented Estimated counter figures as of 2026-08-17, not live, valued at the $5/MTok Claude Opus input rate. All four only grow, so read them as floors. Live at jcodemunch.com.

Works with Claude Code, Cursor, VS Code, Codex CLI, Windsurf, Continue, and any MCP-compatible client.

Install now · Quickstart · See the evidence · Pricing

PyPI version PyPI - Python Version License MCP Local-first Issues closed DOI

Free for personal use. Use it to make money, and Uncle J. gets a taste. Fair enough? Commercial licenses below. Our guarantee: if jCodeMunch doesn't pay for itself, you don't pay for jCodeMunch.

Small by default. A new install starts on a six-tool front door: menu, order and route do the work, and jcodemunch_guide, announce_model and set_tool_tier help. The full tool set sits behind it, and jcodemunch-mcp surface shows exactly what your install advertises.


Why jCodeMunch?

Most AI agents explore repositories the expensive way: open entire files, skim thousands of irrelevant lines, repeat. That is not "a little inefficient." That is a token incinerator.

jCodeMunch indexes a codebase once and lets agents retrieve only the exact code they need: functions, classes, methods, constants, outlines, and tightly scoped context bundles, with byte-level precision. It parses source with tree-sitter, stores structured symbol metadata (signature, kind, qualified name, summary, byte offsets) alongside raw file content in a local index, and fetches exact implementations on demand instead of re-reading files over and over.

Task Traditional approach With jCodeMunch
Find a function Open and scan large files Search symbol, fetch exact implementation
Understand a module Read broad file regions Pull only relevant symbols and imports
Explore repo structure Traverse file after file Query outlines, trees, and targeted bundles
"What breaks if I change X?" Search for the name, then read each hit get_blast_radius: affected files and symbols, across indexed repos, with no IDE running

Index once. Query cheaply. Keep moving. Precision context beats brute-force context.


Evidence

Reproducible token efficiency benchmark

Measured with tiktoken cl100k_base across three public repos pinned to upstream commits, run 2026-10-22 on v1.108.391 (at commit 15afcf75, whose version string is 1.108.391 but which also carries the settings-file ranking change released in 1.108.392 and the field/constant change released after it). Workflow: search_symbols (top 5) + get_symbol_source × 3 per query. Two baselines, same run, same corpus, same file reader:

  • Grep-top-3: rg -l the query terms, rank files by match count, open the top 3 whole. This is what a competent agent without the tool actually does, and it is the number to quote.
  • Read-all: every indexed source file concatenated. A ceiling nobody pays; retained for continuity with previously published figures.
Repository Files Symbols Grep-top-3 baseline jCodeMunch vs grep vs read-all
expressjs/express 186 989 15,724 avg 990 avg 15.9x 156.1x
fastapi/fastapi 1,186 13,699 85,296 avg 2,556 avg 33.4x 322.9x
gin-gonic/gin 98 1,822 31,975 avg 1,481 avg 21.6x 102.5x
Grand total, pooled (15 task-runs) 664,975 25,132 26.5x 225.2x

Against a grep-and-read agent: 94.5% fewer tokens per lookup on average. No single multiple describes every query; the per-repo rows above are the spread. Against read-all the figure is 99.6%, but nobody pays that ceiling. Compact MUNCH wire encoding then trims a median 45.5% more bytes off responses.

Full methodology, pinned commits, harness, and known caveats: benchmarks/METHODOLOGY.md · Reproduce it yourself · TOKEN_SAVINGS.md

Independent A/B test on a production codebase

50-iteration A/B test on a real Vue 3 + Firebase production codebase, jCodeMunch vs native tools (Grep/Glob/Read), Claude Sonnet 4.6, fresh session per iteration: success rate 80% vs 72%, timeout rate 32% vs 40%, mean cache creation down 10.5%. Tool-layer savings isolated from fixed overhead: 15-25%. One finding category appeared exclusively in the jCodeMunch variant: orphaned file detection via find_importers, a structural query native tools cannot answer without scripting. Full report: benchmarks/ab-test-naming-audit-2026-03-18.md

Mentioned by

Full recognition page →


Install

One-click installs

Install in VS Code Install in VS Code Insiders Install in Cursor

uv tool install jcodemunch-mcp
jcodemunch-mcp init

No virtualenv to manage, nothing written into system Python, and it works as-is on PEP 668 distros (Ubuntu 24.04+, Debian 12+) where bare pip install is refused. Don't have uv yet?

init auto-detects your MCP clients (Claude Code, Claude Desktop, Cursor, Windsurf, Continue, Codex, opencode, Gemini CLI, Cline, VS Code with Copilot), writes their config entries, installs the hooks that keep the index fresh without adding anything to the model's context (re-index after an edit, a pre-compaction checkpoint, a task-complete note to you), optionally indexes your project, and audits your agent config files for token waste. Two extras are opt-in because the model reads them on every turn they apply: --policy writes the Code Exploration Policy into CLAUDE.md, AGENTS.md and the Cursor and Windsurf rules files, and --guidance adds the hooks that advise the model on Read/Grep/Glob/Bash, brief subagents and restore context after compaction. With the PreToolUse hook installed (--guidance or --strict) and JCODEMUNCH_HOOK_GREP_ANSWER=1, a large Grep inside an indexed repo is answered from the index once: the hook refuses it with every match counted as the reason (by file and by function or class, with less detail for a very large set; the lines themselves are not included; the answer says it came from the index, how many lines in how many files match the pattern case-insensitively, and that JCODEMUNCH_HOOK_GREP_ANSWER=0 turns it off), and the same Grep sent again runs normally. A Grep under the size thresholds (JCODEMUNCH_HOOK_GREP_ANSWER_MIN_LINES, JCODEMUNCH_HOOK_GREP_ANSWER_MIN_FILES) runs untouched, and so does any Grep on an index the file cap cut short. It is off by default. An install that already has them keeps them; jcodemunch-mcp init --remove-guidance removes them, with backups.

Ask for it by name. Tell your agent to use jcodemunch ("use jcodemunch to find where X is handled"). In the sessions we measured, agents used it when the user asked for it by name.

Other install paths
Command Use it when
uvx jcodemunch-mcp Zero install. Runs from an ephemeral environment — nothing lands on disk permanently. The client entries init writes already invoke the server this way, so for most setups this is all that ever runs. ⚠ Enforcement hooks are the exception: they're spawned by a minimal-PATH subshell and resolve the executable by name, so they need uv tool install (or pipx/pip) to work.
pipx install jcodemunch-mcp You already standardise on pipx
pip install jcodemunch-mcp Inside a virtualenv you manage yourself

Verify:

jcodemunch-mcp --version

Manual Claude Code setup

claude mcp add -s user jcodemunch -- uvx jcodemunch-mcp

No install step — uvx fetches and runs the server on demand. Prefer it on your PATH (and required for enforcement hooks)? uv tool install jcodemunch-mcp, then claude mcp add -s user jcodemunch jcodemunch-mcp.

Then tell the agent to prefer the tools. This matters more than people think; installation makes the tools available but does not break the agent's brute-reading habit. One line in your CLAUDE.md does it:

Call the jcodemunch_guide tool and strictly follow its instructions.

Using Cursor, Windsurf, Codex CLI, JetBrains AI Assistant, Junie, Antigravity, Gemini CLI, Qwen Code, Kiro, Cline, Zed, Goose, Hermes, Odysseus, or Paperclip? Every tested client configuration lives in CLIENTS.md, along with fewer approval prompts, a committed .mcp.json for your team and a shared HTTP server. Optional extras (local semantic search, AI summaries per provider) are in QUICKSTART.md; the system surfaces each extra pulls in are documented in SECURITY.md.


Quickstart

Full walkthrough: QUICKSTART.md. The two-minute version, inside your agent after init:

  1. Ask: "Index this repo with jcodemunch."
  2. Ask: "Using jcodemunch, find the function that handles authentication and show me its source."

The agent should answer via search_symbols and get_symbol_source, returning tens of lines instead of whole files. Confirm with get_session_stats: it reports tokens served and savings for the session. That is where the numbers on the meter come from.

Want to skip initial indexing for popular frameworks? Pre-built starter packs: jcodemunch-mcp install-pack --list (free packs need no license).

See it on Express (free)

  1. Install and set up your client: uv tool install jcodemunch-mcp, then jcodemunch-mcp init
  2. Load the free starter pack Node.js Essentials (Node, Express, Fastify, Koa): jcodemunch-mcp install-pack nodejs. Free packs need no license.
  3. Ask your agent: "Using jCodeMunch, find where Express registers a route handler and show me that function."

What that lookup costs, from our benchmark on Express at commit 1faf2289, counted with cl100k:

Tokens
Grep-and-read: search router route handler, open the top 3 matching files whole 9,890
jCodeMunch: one symbol search, then the source of the top 3 matches 1,074

That's one of the 15 lookups in the benchmark (5 each on express, fastapi and gin at pinned commits). jCodeMunch used 94.5% fewer tokens per lookup on average than grep-and-read on our 15-lookup benchmark. The pack is built from Express 4.x, while the benchmark pins commit 1faf2289 on upstream main, so your count can differ. To rerun the benchmark at the pinned commits, follow benchmarks/REPRODUCING.md; raw data is in benchmarks/.


What you can do

  • Retrieve one symbol instead of loading a file. get_symbol_source returns the exact function body, byte-precise, for the majority of edits that touch one function in a 700-line file (~95% savings on that read). A class comes back as an outline, each method collapsed to its signature; pass class_body="full" for the whole body.
  • Assemble a whole task's context in one call. assemble_task_context classifies the task intent, extracts anchor symbols, and runs the right tool sequence under one token budget. plan_turn routes the turn before the first read.
  • Ask structural questions grep can't answer. find_importers, get_blast_radius, get_call_hierarchy, find_dead_code, get_changed_symbols, get_hotspots, search_ast anti-pattern sweeps, and more. Two of them sound alike and are not: check_references answers where a name is used (import sites plus every file whose content mentions it), find_references answers who imports it, over the import graph alone, so a call site is invisible to it. get_call_hierarchy says which callers are direct: a deeper row names the caller it is reached from.
  • Preflight risky changes, and know when to stop. check_edit_safe, check_delete_safe, get_pr_risk_profile, and plan_refactoring with edit-ready {old_text, new_text} blocks. The two safety checks return stop_rule.terminal: true means no further jcodemunch call moves the verdict, so re-running find_importers or check_references to be sure is wasted work. It means final, not safe. corpus_inadequate (the index could not back an absence claim) and dynamic_import_boundary (a dynamic import, or for a .NET control or build item a path the index does not carry, can load the file) are never terminal, and each tool's description lists every verdict it returns. check_rename_safe answers safe: null rather than true when the import graph could not reach the symbol's file, so the files that use it were never checked, and get_pr_risk_profile answers risk_score: null with unmeasurable_axes when it could not measure the blast axis; a CI gate should fail on null. Hand the server your type checker's own output (jcodemunch-mcp import-trace --diagnostics <file>: mypy --output json, pyright --outputjson, tsc --pretty false, ruff --output-format json) and check_edit_safe, get_changed_symbols, get_pr_risk_profile and get_symbol_provenance say which symbols the checker already flags, as of which commit. Nothing runs a checker for you. False names the specific thing that would change the answer.
  • Trust the answers. Calibrated confidence scores, freshness flags, coverage contracts on absence claims, compiler-verified references via SCIP import, and automatic secret redaction before anything reaches the LLM.
  • Keep the index fresh automatically. Watch modes, agent hooks, and a VS Code extension close the staleness gap.

That's the highlight reel. The complete tour of the full tool set (90+ tools behind the six-tool front door), the MUNCH compact wire format, evidence receipts, offloadable-work annotation, and the session-economics instrumentation is in CAPABILITIES.md, with internals in UNDER_THE_HOOD.md.

What's new

  • v1.108.400 (2026-10-27) — a text search returns the code it found, and a retired tool name says what replaced it
  • v1.108.399 (2026-10-26) — four core tool descriptions open with the question each tool answers
  • v1.108.398 (2026-10-25) — the semantic and all extras install a fixed filelock on every Python
  • v1.108.397 (2026-10-24) — a cut search names the files it left off, and file_pattern takes braces

When does it help (and when doesn't it)?

Scenario Native tool jCodeMunch Savings
Edit one function (700-line file) Read → 700 lines get_symbol_source → 30 lines ~95%
Understand a file's structure Read → full content get_file_outline → names + signatures ~80%
Find which file to edit Grep many files search_symbols → exact match comparable
Edit requires whole-file context Read → full content get_file_content → full content ~0%
"What breaks if I change X?" Grep the name, Read each hit get_blast_radius → affected files and symbols not measured

It helps most on targeted edits (one function, one method, one class), which is the majority of real editing work. Edits that genuinely require the entire file (restructuring file-level state, reordering logic spanning hundreds of lines) see no advantage. Best fits: large repositories, unfamiliar codebases, agent-driven exploration, refactoring and impact analysis, and teams cutting AI token costs without making agents dumber.

Languages: 70+ via tree-sitter, including Python, JavaScript/TypeScript, Go, Rust, Java, C/C++, C#, PHP, Ruby, Swift, and Kotlin. Full matrix: LANGUAGE_SUPPORT.md. Monorepos: yes; incremental indexing, workspace-member detection, subpath scoping.


If you reach jCodeMunch through the MCP connector on a model that supports tool search, you can keep our schemas out of your context prefix entirely and let Claude load only the two or three tools a request needs. You do not set defer_loading per tool — set it once for the whole server:

{
  "mcp_servers": [
    { "type": "url", "url": "https://your-host/mcp", "name": "jcodemunch" }
  ],
  "tools": [
    { "type": "tool_search_tool_bm25_20251119", "name": "tool_search_tool_bm25" },
    {
      "type": "mcp_toolset",
      "mcp_server_name": "jcodemunch",
      "default_config": { "defer_loading": true },
      "configs": {
        "resolve_repo":       { "defer_loading": false },
        "search_symbols":     { "defer_loading": false },
        "get_ranked_context": { "defer_loading": false }
      }
    }
  ]
}

Send it with the beta header mcp-client-2025-11-20. Both halves are required — mcp_servers alone is a validation error, and so is mcp_toolset without the matching mcp_server_name.

⚠ The MCP connector takes a URL, so this applies to jCodeMunch served over sse or streamable-http (jcodemunch-mcp serve --transport streamable-http), not to the default local stdio setup. On stdio, whether schemas are deferred is up to your client, and tool_surface: "counter" below is the lever you control.

The configs block above follows Anthropic's own advice — keep your 3–5 most-used tools resident so common requests skip the search round trip — and per-tool configs overrides default_config.

A deferred tool is found by searching its name and description, so the core descriptions open with the question each tool answers, in the words an agent uses: search_symbols "find where a function, class or method is defined", get_symbol_source "read or show the source code", get_call_hierarchy "who calls this function or method", check_references "where is a function, class or other identifier used". The analysis tools follow the same rule: check_delete_safe opens "is it safe to delete this function", get_pr_risk_profile "how risky is this pull request", get_hotspots "where is the riskiest code".

Deferred definitions are excluded from the system-prompt prefix and appended inline as tool_reference blocks when Claude discovers them, so prompt caching is preserved — this is not the cache-invalidating kind of dynamic tool list. At least one tool in the request must stay non-deferred, or the API returns a 400.

⚠ This is a different mechanism from our own tool_surface: "counter", and you do not need both. Tool search is host-side and works across every MCP server you have connected; the Counter is server-side, works on any host including ones with no tool-search support, and is what init configures on a first-ever install. Pick whichever your host supports — see CONFIGURATION.md for the Counter and jcodemunch-mcp surface for what your install actually advertises.


Custom subagents

A Claude Code subagent gets the session's MCP tools unless its definition has a tools: list. If yours does, the subagent can call only what that list names, so add the jcodemunch tools you want:

---
name: code-explorer
description: Finds where code lives and what a change reaches.
tools: Read, Grep, Glob, mcp__jcodemunch__route, mcp__jcodemunch__menu, mcp__jcodemunch__order
---

Those three are the front door on the counter surface, which init sets on a first-ever install. On the full surface, name the tools themselves, for example mcp__jcodemunch__search_symbols. The first line of jcodemunch-mcp surface names the active surface. The mcp__jcodemunch__ prefix assumes the server is registered as jcodemunch, the name init writes; a server registered under another name gets that name in the prefix.


Privacy Policy

jCodeMunch runs on your machine. Your code, file paths and queries stay there: the index lives in ~/.code-index/, and deleting that folder removes it.

The one thing the server sends by default is an anonymous savings counter: a random ID, the tokens saved since the last send, and a lifetime total. It sends no code, no paths and no queries. Turn it off with "share_savings": false in ~/.code-index/config.jsonc or JCODEMUNCH_SHARE_SAVINGS=0. The Claude Code plugin turns it off for you.

Anything else that reaches the network is something you run or turn on yourself, and each is listed in Security, privacy, and background behavior. Full policy: https://jcodemunch.com/privacy.php

Security, privacy, and background behavior

An install that never runs init (a uvx or plugin install) gets one license_notice line in its first tool answer, once per machine; it is skipped with a license key configured, after jcodemunch-mcp config set license_reminder false, after an init that printed the license line, on CI or remote runners (CI=true, CLAUDE_CODE_REMOTE=true), or with JCODEMUNCH_LICENSE_NOTICE=0. Its link carries a fixed source tag, utm_medium=notice.

A short work-license reminder follows, 7 days after a machine's first index and then at most every 30 days: on stderr after a CLI command a person runs (only at a terminal, never with --json), and as license_notice on the first tool answer of a server process when due. Its state is ~/.code-index/license_reminder_state.json (three fields: first index seen, last shown, count). It is never shown with a license key configured, on CI or remote runners, or after jcodemunch-mcp config set license_reminder false; JCODEMUNCH_LICENSE_REMINDER=0 also silences it. Nothing is sent. Its buy link carries a fixed source tag (utm_medium=reminder, or utm_medium=tool in a tool answer), the same on every machine, which reaches the site only if the link is opened.

The text report of jcodemunch-mcp receipt ends with one license line on a machine with no license key, tagged utm_medium=receipt. It has no clock and writes no state; every switch that silences the reminder silences it, and --export and --explain never carry it.

The short version is the Privacy Policy above. Local-first by design: indexes live at ~/.code-index/, and the base package's only default network behavior is an anonymous savings counter (random ID plus aggregate token counts, no code, no paths, no PII; opt out with share_savings: false). Everything the server does beyond answering a tool call (file watching, the opt-in login service, license validation, model downloads, org reporting) is opt-in or opt-out, visible, and reversible, and every item is enumerated in SECURITY.md alongside the path-traversal, symlink, and secret-redaction controls. A stdio server also stops on its own when the client process that started it is gone, even if its stdin pipe stays open (JCODEMUNCH_PARENT_WATCH_SECONDS=0 turns that off). A default init writes no policy file and installs no hook whose output the model reads; those are init --policy and init --guidance, and init --remove-guidance takes them back out of an older install. init --git-hook adds a git post-checkout hook that re-indexes the files a branch switch changed, in an already indexed repository; uninstall run in that repository removes it.

Grammar pack override (#608). The dependency tree-sitter-language-pack is pinned <1.0.0 because the 0.x wheels bundle every grammar and parsing stays local. F# is the one exception: it is parsed by the pinned tree-sitter-fsharp wheel, which also compiles its grammar in, so F# parsing stays local on either pack (#848). You can override it with pip install -U tree-sitter-language-pack after installing; nothing in the code refuses it. What you accept, measured against 1.17.0 on 2026-09-11: the 1.x pack ships no grammars and fetches each one over the network into its cache directory (measured on Windows: %LOCALAPPDATA%\tree-sitter-language-pack\v<version>\libs; jcodemunch-mcp install-status prints the path on any platform) the first time a language is parsed, so an airgapped install parses nothing, and the nim grammar changed upstream, so nim files yield no symbols (the manifest also lacks autohotkey, ejs and verse, which costs nothing here: those three are parsed by jCodeMunch's own extractors, not by tree-sitter). An install on a 1.x pack says so: every index_folder result carries a grammar_pack block and a warning naming the version, the cache directory and each language whose grammar failed, and jcodemunch-mcp install-status prints the same. Dropping the pin is a separate decision that needs the offline story first.


Per-project configuration

Most settings live in the global ~/.code-index/config.jsonc, but any of them can be overridden for a single repository by dropping a .jcodemunch.jsonc at its root. It is an overlay: keys it declares win, keys it omits fall through to global and then to the built-in default, so it only needs to contain what differs.

// <your-repo>/.jcodemunch.jsonc
{
  "max_file_size": 1048576,
  "languages": ["python", "typescript", "racket"]
}

Declaring Racket defining forms

Racket projects routinely define their own defining forms with define-syntax, and a static parser cannot know what those bind — (defstep (check-admin) ...) is indistinguishable from a function call. Declaring them makes their bindings searchable:

{
  "racket_definition_forms": {
    "defstep":  "function",
    "defstudy": "constant",
    "defvar":   "constant",
    "define-schema": "class"
  }
}

Each entry maps a form name to what it binds: function, constant, class or type. Where the name sits is read from the source rather than declared — (defstep (check-admin) ...) takes the head of the parameter list, (defstudy consent ...) takes the bare symbol — so a form that appears in both shapes works either way.

⚠ This is an assertion, not something jCodeMunch can verify. A wrong declaration puts a name in the index that Racket does not actually bind. Declarations are also matched only after every built-in form, so declaring define or struct has no effect — the built-in handling wins.

Declaring what a Racket #lang looks like

A #lang line names a reader, and jCodeMunch's Racket parser reads S-expressions. The distribution's langs are built in (racket/*, typed/racket*, s-exp, info, at-exp …, and the document langs scribble/*, pollen, punct, markdown …), but a project's own lang is unknown to it and is treated as a document — no symbols, still text-searchable — until you say what its syntax is:

{
  "racket_langs": {
    "conscript": "at-exp",
    "mylang": "sexp"
  }
}

sexp is plain S-expressions; at-exp is at-exp text bodies over Racket (read with @ as the command character, exactly as #lang at-exp reads them, so prose containing ; " # or | is prose); text is a document language that is never walked. A key also covers its sub-langs (conscript matches conscript/with-require), and a project may demote a lang as well as promote one. An at-exp lang whose reader uses another command character declares it with the object form — "mylang": {"tier": "at-exp", "command_char": "◊"} — the way Racket's make-at-readtable takes #:command-char.

Both keys change what the parser emits for unchanged files, so a change to either is stamped on the index and forces one full re-parse on the next index (rebuild_reason: "racket_config_changed"); you do not need to touch the files or clear the index. An index holding Racket files that was built before this stamp existed re-parses once the same way (rebuild_reason: "racket_index_predates_gate").


Documentation

Doc What it covers
QUICKSTART.md Zero-to-indexed in three steps
CLIENTS.md Tested configuration for every MCP client
USER_GUIDE.md Full tool reference, workflows, and best practices
CAPABILITIES.md The complete capability reference beyond the highlight reel
CONFIGURATION.md

…

Releases

Recent versions

All releases ↗
  1. v1.108.422v1.108.422 — the shared parse cache never serves what an older parser emitted
  2. v1.108.421v1.108.421 — a starter pack installs in a few megabytes, and a file tree costs a third of the characters
  3. v1.108.420v1.108.420 — re-indexing one file by path keeps a partial index marked partial
  4. v1.108.419v1.108.419 — the file cap limits what one call parses, not what the index keeps
  5. v1.108.418v1.108.418 — a search on a capped index says, in its answer, that the index is partial
  6. v1.108.417v1.108.417 — a wrong call through order names a call that works