agentmap
Health Gecti
- License — License: MIT
- Description — Repository has a description
- Active repo — Last push 0 days ago
- Community trust — 45 GitHub stars
Code Basarisiz
- process.env — Environment variable access in .github/workflows/deprecate.yml
- fs module — File system access in .github/workflows/deprecate.yml
- network request — Outbound network request in .github/workflows/deprecate.yml
- execSync — Synchronous shell command execution in benchmark/bench.mjs
- eval() — Dynamic code execution via eval() in eval/eval.mjs
- exec() — Shell command execution in eval/eval.mjs
Permissions Gecti
- Permissions — No dangerous permissions requested
Bu listing icin henuz AI raporu yok.
Stop your coding agent reading the wrong files. Compiler-grade TS/JS repo map — 100% precision on blast radius vs grep's 60%, measured on public repos. CLI + MCP server, fully local, no vector DB.
agentmap
Stop your coding agent from reading the wrong files.
Ask "what breaks if I change this?" and grep hands back a pile where 40% of the
files don't actually depend on it. agentmap answers the same question at 100%
precision — measured, on public repos, reproducibly.
npx @raymondchins/agentmap --relates src/lib/auth.ts
Your agent re-learns your codebase every session, grepping to find what connects to
what and burning tokens before it writes a line. agentmap gives it a queryable,
PageRank-ranked import/symbol map instead — built with ts-morph, the real
TypeScript compiler, so it resolves what string matching cannot.
| Question | agentmap | git grep |
|---|---|---|
| What depends on this file? | 100% precision, 99.2% recall | 59.9% precision |
| Where is this symbol defined? | 53.3% top-1, 93.3% top-3 | 32% top-1, 80% top-3 |
| Tokens to find a definition | ~2.4× fewer | — |
n=42 dependents / n=75 definitions across zod, zustand and hono at pinned commits. Ground truth is derived at runtime by an independent resolver, not hand-authored. Re-run it yourself: npm run eval. Full method + per-repo numbers: EVAL.md.
Precision is the point: every wrong file your agent opens is context spent being
misled. --relates returns the full blast radius, so it costs more tokens than a
bare grep -l file list — and that trade is stated plainly in the eval,
not hidden.
One file, one runtime dependency (
ts-morph, which bundles the TypeScript compiler — ~10 MB installed). No vector DB, no embedding API, no server.npx @raymondchins/agentmap --any <query>and you have a ranked answer.Fully local — no network calls, no telemetry, no data leaves your machine. agentmap
reads your code, writes a cache under.claude/agentmap/, and never phones home (there is
not a singlefetch/httpcall in the source). Your code is never sent anywhere.⚠️ Always install the scoped name:
@raymondchins/agentmap.npx agentmap
(unscoped) runs an unrelated package by a different author — this project is@raymondchins/agentmap, and the scoped name is required in every install and command.npmjs.com/package/@raymondchins/agentmap
Quickstart
No install needed:
npx @raymondchins/agentmap --any <query>
…or run it directly from a checkout:
node agentmap.mjs --any <query>
The first run builds and caches the map to .claude/agentmap/map.json (add.claude/agentmap/ to .gitignore). Subsequent runs serve the cache when the tree is clean and HEAD is
unchanged, and silently rebuild from disk when there are uncommitted .ts/.tsx/.js/...
edits — so queries always reflect your in-flight work.
Run with no flag to build + print a one-line summary:
$ node agentmap.mjs
agentmap: 154 files | 4 features | top hub: lib/utils.ts (deg 52, pr 0.105171)
Benchmark
Every task you hand a coding agent starts with the same hidden step — find the relevant code.
Here's the token cost of that step, reading raw files vs querying agentmap, on a real 154-file
Next.js app (vercel/ai-chatbot). Every figure is captured
tool output (node benchmark/bench.mjs <repo> at the pinned sha):
| The question the agent has to answer first | Reading files | With agentmap | Saved |
|---|---|---|---|
| Where is this symbol defined? | 1,950 | 20 | 99% |
| Does a helper for this already exist? (reuse) | 14,740 | 19 | 99.9% |
| What breaks if I change this file? (blast radius) | 81,038 | 616 | 99.2% |
| What files make up this feature? | 6,121 | 1,025 | 83.3% |
| Give me a repo overview | 3,065 | 1,127 | 63.2% |
| Load the whole repo into context | 150,281 | 1,127 | 99.3% |
| What does this one file import? | 583 | 517 | 11.3% |
| All 7 tasks combined | 257,778 | 4,451 | 98.3% |
Context tokens the agent burns to answer each question — token est = chars/4, applied to both sides.
That's the agent reaching the same answer on 58× fewer tokens overall — and the pattern holds
across zod (367 files, 99.2%) and
taxonomy (125 files, 96.0%), peaking at 646× fewer
on a single whole-repo map. Reproducible at pinned shas; full per-scenario tables in./benchmark/RESULTS.md.
Methodology note: the 58× overall figure is dominated by the whole-repo-load scenario
(Scenario F — 150 K vs 1 K tokens), which skews the combined ratio sharply upward. Excluding it,
the per-task overall ratio on the same sample repo is approximately 32×. Both numbers are real;
the headline captures the most common agent worst-case (repo-dump on session start), while the
per-task average better represents typical individual queries. RESULTS.md has the full breakdown.
Fewer tokens, but are they the right tokens? Token efficiency is only half the story — a
separate EVAL.md (npm run eval) scores retrieval accuracy against ground
truth derived live from real repos (zod, zustand, hono). Headline: agentmap returns the symbol
definition in the top 3 93.3% of the time (naive grep 80%) at ~2.4× fewer tokens, and
identifies a module's dependents at 100% precision / 99.2% recall (grep 100% recall but 59.9%
precision). Fixtures are pinned to exact commits, so those numbers are re-derivable rather than
whatever upstream happened to look like the day they were taken. Honest tradeoffs and method in
EVAL.md.
Speed: a cold build (parse + PageRank + symbol graph) takes ~1.2s; a warm cached query
returns in ~0.1s (the lazy-loaded path added in 0.2.2) — the agent has a ranked answer back
before it would have finished opening the first handful of files.
Honest notes: the win scales with the work — the small rows above (63%, 11%) are the floor, and a
trivial single-file lookup can even cost more than cat+grep (taxonomy's file-import task
hit −313%; we leave it in). Numbers measure context-token volume, not answer quality or wall-clock.
Why it's different
Many "repo context" tools are a photocopy: they dump your repository (or a slice of it) into
the prompt once and walk away — the copy goes stale the moment you edit a file, and nothing
makes the agent actually read it. agentmap is queryable and ranked instead: the agent
interrogates it flag-by-flag rather than swallowing a dump.
But the real reason to reach for agentmap is accuracy. It's built on ts-morph — the actual
TypeScript compiler — so its import graph resolves the things a text/tree-sitter scanner guesses
at: tsconfig/jsconfig paths, vite/vitest/webpack resolve.alias, package.json Node#imports subpaths, and pnpm/npm/yarn workspace cross-package imports. It reports anedgeCoverage map-health signal and warns loudly when a repo's imports mostly don't resolve,
so a broken map is never framed as success — and a separate EVAL.md scores
retrieval accuracy against live ground truth. That compiler-grade precision on TS/JS is the wedge.
The self-refreshing side — a post-commit rebuild plus a PreToolUse hook that steers the agent
to the map before it serial-greps — is genuinely useful, but it isn't unique: CodeGraph
(colbymchenry/codegraph, ~57k★) ships a native
OS-event file watcher (FSEvents/inotify) with debounced auto-sync and an installer that
auto-configures eight agent CLIs. agentmap's honest edge over the multi-language graph tools is
narrower and sharper: TS/JS resolution the others approximate, with a published accuracy eval.
| agentmap | Aider repo map | RepoMapper | Repomix | code2prompt | |
|---|---|---|---|---|---|
| Ranking algorithm | Personalized PageRank (file + symbol graphs) | PageRank (graph ranking) | Importance heuristics | None (file order) | None (file order) |
| Languages | TS/JS + Vue SFC (via ts-morph) | Many (tree-sitter) | Many (tree-sitter) | Language-agnostic (text) | Language-agnostic (text) |
| Token-budget output | Yes — --map [--tokens N] ranked digest |
Yes (built into Aider's context) | Partial | Yes (size caps) | Yes (templates/caps) |
| TS/JS resolution depth | Compiler-grade — tsconfig paths + vite/webpack alias + #imports + workspaces (ts-morph) |
Basename/regex heuristics | Basename/regex heuristics | N/A (text) | N/A (text) |
| Retrieval-accuracy eval | Yes — published EVAL.md vs live ground truth |
No | No | No | No |
| Agent-loop wiring | Yes — post-commit auto-refresh + PreToolUse hook | In-process (Aider only) | No | No | No |
| Dependencies | ts-morph only |
Python + tree-sitter stack | Python + tree-sitter | Node | Rust binary |
| Install | npx @raymondchins/agentmap |
pip install aider-chat |
pip install |
npx/global |
cargo/binary |
What that table is not claiming: agentmap is TS/JS-only (the others are multi-language),
and it's a file-level import graph, not a full call-site/reference resolver (see
Scope & limitations). The differentiators are narrow and honest:
(1) compiler-grade TS/JS resolution (aliases, vite/webpack, #imports, workspaces) with a
published accuracy eval, and (2) the --any router. The agent-loop wiring is real and
convenient but not unique — CodeGraph and others
auto-sync and auto-configure agent CLIs too; we don't claim it as a moat.
The agent loop (staying current, staying used)
A common failure of repo-map tools: they build a beautiful map, and then the
agent forgets it exists and greps anyway. A map the agent doesn't open is just dead weight.
agentmap closes that loop. Two hooks (in ./hooks/) do the work: the map
refreshes itself after every commit, and the agent gets nudged to query it before it
serial-greps. You wire it once — then it stays current on its own, and stays used.
This wiring is table stakes, not the moat — CodeGraph
and other tools also auto-sync (via native OS file watchers) and auto-configure agent CLIs.
agentmap ships it because it's genuinely useful; the actual point of agentmap is the
compiler-grade TS/JS accuracy the map is built on.
1. Auto-refresh on commit
hooks/post-commit rebuilds .claude/agentmap/map.json after each
commit, detached + silenced so it never slows the commit. It skips during
rebase/merge/cherry-pick and no-ops if Node is missing.
The hooks ship inside the npm package. The simplest setup:
npx @raymondchins/agentmap --install-hooks
This copies hooks/post-commit into .git/hooks/, sets it executable, ensures.claude/agentmap/ is in .gitignore, and auto-wires the PreToolUse nudge
hook into .claude/settings.json (merge-safe + idempotent) so map enforcement is
on by default — no manual paste. Manual alternative for just the post-commit hook:
# from your repo root
cp hooks/post-commit .git/hooks/post-commit
chmod +x .git/hooks/post-commit
The hook resolves the builder to the installed package — node_modules/.bin/agentmap,
a PATH agentmap binary verified to be @raymondchins/agentmap, thennpx @raymondchins/agentmap. It never runs a repo-local ./agentmap.mjs unless you opt in
with AGENTMAP_HOOK_ALLOW_LOCAL=1 (for developing agentmap itself), so an
attacker-planted agentmap.mjs can't execute on your next commit.
2. Force the agent to use it — PreToolUse hook
hooks/agentmap-nudge.mjs is a non-blocking hook for
Claude Code that covers both the Grep tool and raw Bash text-searchers
(grep/rg/egrep/fgrep/ag/ack). When either looks like a dependency /
who-imports / component-usage / reuse / where-is-symbol search, it injects a reminder
steering the agent to agentmap --any first. It never denies the call, and stays silent
for raw-string / Tailwind-class / lowercase-HTML-tag sweeps and for pipe-filtered commands
like ps aux | grep node — so it's high-signal, not nagging.
Fires on: import/require/export/from '...' patterns, JSX component tags
(<Hero, <ProviderCard), explicit intent words (where is, who imports, reuse,existing component), and — in both the Grep tool and the Bash branch — bare multi-hump
PascalCase identifiers (ProviderCard, TopProviders) that almost always mean "where is
this symbol / who uses it". The Bash branch additionally only fires when the searcher is the primary command (at the start,
or after ;/&&); piped log-filters stay silent.
All four nudge/gate variants (this one, Codex, Gemini, OpenCode) also self-gate on
project presence: since they ship at user/global scope too (plugin bundle, ~/.gemini,~/.codex, ~/.config/opencode), they walk up from the tool call's cwd to the
filesystem root looking for node_modules/@raymondchins/agentmap or a built.claude/agentmap/map.json before doing anything else, so a repo with no agentmap stays
silent instead of nagging (or, for Codex, denying a grep it has no business denying).
--install-hooks writes both matchers into .claude/settings.json for you (merge-safe —
preserves existing settings, won't duplicate on re-run). The single hook file dispatches
internally on tool_name. For reference, or to wire it by hand:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Grep",
"hooks": [{ "type": "command", "command": "node ./hooks/agentmap-nudge.mjs" }]
},
{
"matcher": "Bash",
"hooks": [{ "type": "command", "command": "node ./hooks/agentmap-nudge.mjs" }]
}
]
}
}
That's the "forced to use it" in the tagline: the map stays current on its own, and the
agent is steered to it the moment it reaches for a dependency-shaped grep or Bash search.
3. Agent skills (Cursor, Claude Code, Codex, OpenCode, Gemini, Antigravity, Copilot)
npx @raymondchins/agentmap --install-skill
…or grab just the skill (no agentmap flags) via the skills
CLI — agentmap ships the skills/agentmap/SKILL.md layout it expects:
npx skills add raymondchins/agentmap
--install-skill copies packaged SKILL.md files and a Cursor rule (.cursor/rules/agentmap.mdc,alwaysApply: true) into the current repo or global agent directories. Paths follow
each platform's official skill-directory conventions. Options:
agentmap --install-skill --platform cursor # Cursor rule only (project)
agentmap --install-skill --platform claude # .claude/skills/agentmap/SKILL.md
agentmap --install-skill --platform codex # .codex/skills/ (project) or ~/.codex/skills/ (global)
agentmap --install-skill --platform opencode # .opencode/skills/ (project) or ~/.config/opencode/skills/ (global)
agentmap --install-skill --platform gemini # .gemini/skills/ (project); global ~/.gemini/skills/ (Windows global: ~/.agents/skills/)
agentmap --install-skill --platform antigravity # .agents/skills/ (project) or ~/.gemini/config/skills/ (global)
agentmap --install-skill --platform copilot # .copilot/skills/ or ~/.copilot/skills/
agentmap --install-skill --global --platform claude # ~/.claude/skills/...
agentmap --install-skill --platform agents # legacy .agents/skills/ (project or global); excluded from default `all`
agentmap --install-skill --dry-run # preview paths, no writes
--platform all installs: claude, cursor, codex, opencode, gemini, antigravity, copilot (not legacy agents).
Some platforms also get always-on docs and hooks in the same command:
--platform |
Skill | Also installs (project) | Global docs |
|---|---|---|---|
gemini |
.gemini/skills/…/SKILL.md |
GEMINI.md + .gemini/settings.json BeforeTool nudge |
~/.gemini/GEMINI.md |
codex |
.codex/skills/…/SKILL.md |
AGENTS.md merge-safe <!-- agentmap:begin/end --> block |
~/.codex/AGENTS.md |
opencode |
.opencode/skills/…/SKILL.md |
AGENTS.md + .opencode/plugins/agentmap-nudge.js |
~/.config/opencode/AGENTS.md |
Codex and OpenCode share one repo-root AGENTS.md on project install. Existing content outside the marked block is preserved.
Pair with --install-hooks (Claude Code) or --mcp (Cursor MCP).
4. Claude Code plugin (one-command bundle)
Prefer the plugin over --install-skill/--install-hooks if you're on Claude Code and
want the skill, the PreToolUse grep/Bash nudge, and the stdio MCP server in a single
install that auto-updates:
# in Claude Code
/plugin marketplace add raymondchins/agentmap
/plugin install agentmap@agentmap
The plugin bundles: the packaged SKILL.md, the PreToolUse nudge (both the Grep
tool and Bash text-searchers, via ${CLAUDE_PLUGIN_ROOT}), and the stdio MCP server
(npx -y @raymondchins/agentmap --mcp, so ts-morph is fetched on demand — the plugin
cache ships no node_modules).
One thing the plugin can't do: install the git
post-commithook. Claude Code
plugins can't write into.git/hooks/, so the auto-refresh-on-commit still needs a
one-timenpx @raymondchins/agentmap --install-hooksin each repo (it also wires the
nudge into.claude/settings.json, harmlessly redundant with the plugin's copy).
Without it the map still rebuilds on any dirty query — you just lose the commit-time
refresh.
Onboarding by platform
Enforcement isn't uniform — some CLIs get a live hook that actively steers grep to
agentmap, some get an MCP server the agent can call, and some are docs-only (a
skill/rule the agent may or may not consult). Honest matrix:
| Platform | Install | Enforcement | Known gaps |
|---|---|---|---|
| Claude Code | /plugin install agentmap@agentmap (or --install-hooks) |
live hook — PreToolUse nudge on Grep + Bash searchers |
non-blocking (never denies grep); bare-symbol Grep nudge requires the #3 hook fix |
| Gemini CLI | --install-skill --platform gemini |
live hook — .gemini/settings.json nudge |
fires on the AfterTool/systemMessage path (the earlier BeforeTool + additionalContext combo was silently dropped — fixed in #4) |
| OpenCode | --install-skill --platform opencode |
log-only — .opencode/plugins/agentmap-nudge.js writes to the log, does not inject context |
plugin can't steer the model; relies on the AGENTS.md block being read |
| Cursor | --install-skill --platform cursor + .cursor/mcp.json (below) |
MCP + docs — alwaysApply rule + the MCP server |
Cursor's own hooks aren't wired; the rule is advisory |
| Codex CLI | --install-skill --platform codex |
live gate — .codex/config.toml PreToolUse hook |
denies only high-confidence structural greps; allow-fallback for logs/pipes/non-TS-JS; AGENTMAP_CODEX_GATE=0 bypasses; needs a trusted dir + Codex hooks-GA |
| Copilot CLI | --install-skill --platform copilot |
docs-only — .copilot/skills/ |
same as Codex — no live hook yet |
Cursor MCP — copy-paste .cursor/mcp.json (Cursor's --mcp wiring is a documented
dead-end otherwise; drop this at your repo root):
{
"mcpServers": {
"agentmap": {
"command": "npx",
"args": ["-y", "@raymondchins/agentmap", "--mcp"]
}
}
}
Then Cursor exposes the 11 query tools (any, find, relates, map, hubs,features, feature, symbols, search, callers, calls). Run agentmap --doctor any time to see what's wired
vs missing.
Uninstall
agentmap only writes files into your repo/home — remove them to fully uninstall. agentmap --doctor lists every path it wrote, and every docs merge lives inside an<!-- agentmap:begin/end --> (or # agentmap:begin/end) fence, so deleting just that block
leaves the rest of your AGENTS.md / GEMINI.md intact.
| Platform | Remove |
|---|---|
| Claude Code | .claude/skills/agentmap/ + the agentmap PreToolUse block in .claude/settings.json |
| Cursor | .cursor/rules/agentmap.mdc + the agentmap entry in .cursor/mcp.json |
| Codex | .codex/skills/agentmap/, the # agentmap:begin/end block in .codex/config.toml, .codex/hooks/agentmap-codex-nudge.mjs, and the fenced block in AGENTS.md |
| OpenCode | .opencode/skills/agentmap/, .opencode/plugins/agentmap-nudge.js, the AGENTS.md block |
| Gemini | .gemini/skills/agentmap/, .gemini/hooks/agentmap-nudge.mjs, the BeforeTool hook in .gemini/settings.json, the GEMINI.md block |
| All | map cache rm -rf .claude/agentmap/; npm devDep npm rm @raymondchins/agentmap; the agentmap block in .git/hooks/post-commit |
Troubleshooting
| Symptom | Cause / fix |
|---|---|
features (0) |
--features only detects Next.js app/ routes; a TanStack src/routes/ repo legitimately shows 0. Use --map / --symbols instead. |
| Empty or wrong map | Usually no tsconfig.json / resolvable aliases in the target repo, so no edges resolved — run agentmap --doctor and check edgeCoverage in --json. |
| Stale-looking results | By design the map rebuilds from disk on a dirty tree / SHA mismatch. Force a rebuild by just running agentmap. |
| Codex/Gemini nudge never fires | Codex's gate is opt-in — set [features] hooks = true in .codex/config.toml (AGENTMAP_CODEX_GATE=0 disables it). Gemini needs the BeforeTool hook that --install-skill writes. |
Installed the wrong agentmap |
This is @raymondchins/agentmap (npm scope) — not the unrelated unscoped agentmap packages. |
| Cursor MCP tools missing | --mcp doesn't auto-wire Cursor; add the copy-paste .cursor/mcp.json from the matrix above and restart Cursor. |
The --any router
Don't want to learn eight flags? You don't have to. Throw anything at --any — a filename, a
function, a feature, even a raw string — and it figures out what you meant, returning the first
layer that hits:
--any <query>
│
├─ 1. FILE exact path → unique basename → unique substring
├─ 2. SYMBOL exported name contains the query (across all files)
├─ 3. FEATURE app/-router feature name contains the query
└─ 4. CONTENT live `git grep` (tracked + untracked) — never stale
Layers 1–3 read the cached structural map (fast, ranked). Layer 4 is a live disk read
via git grep -F, so raw strings, copy, Tailwind classes, and config values the structural
graph never indexes still resolve instead of coming up empty.
Symbol hit (query resolved to a symbol → full block):
$ node agentmap.mjs --any cn
[structure] 1 symbol, 0 feature match for "cn"
lib/utils.ts → cn (FunctionDeclaration)
Ambiguous file hit (query matched multiple files → narrow it):
$ node agentmap.mjs --any utils
[structure] "utils" matched 3 files — narrow it:
lib/utils.ts
lib/db/utils.ts
tests/prompts/utils.ts
Content fallback (no file/symbol/feature match → live git-grep):
$ node agentmap.mjs --any streamText
[content] 13 lines:
app/(chat)/api/chat/route.ts:8: streamText,
app/(chat)/api/chat/route.ts:194: const result = streamText({
artifacts/code/server.ts:1:import { streamText } from "ai";
artifacts/code/server.ts:18: const { fullStream } = streamText({
artifacts/code/server.ts:40: const { fullStream } = streamText({
artifacts/sheet/server.ts:1:import { streamText } from "ai";
artifacts/sheet/server.ts:11: const { fullStream } = streamText({
Commands
Every snippet below is representative output (long lists trimmed) from running agentmap against the public
154-file Next.js repo vercel/ai-chatbot (sha 2becdb4).
--any <q> — the router (file → symbol → feature → live content)
See The --any router above. Default first move for any
"where/what/who" question.
--find <q> — reuse-before-rebuild symbol search
Find every symbol whose name contains the query — exported symbols plus non-exported
top-level declarations. Use it before writing a new util or component to check what already
exists (a private helper counts as reusable too).
$ node agentmap.mjs --find Message
find "Message": 55 match
hooks/use-messages.tsx → useMessages (FunctionDeclaration)
lib/errors.ts → getMessageByErrorCode (FunctionDeclaration)
lib/types.ts → messageMetadataSchema (VariableDeclaration)
lib/types.ts → MessageMetadata (TypeAliasDeclaration)
lib/types.ts → ChatMessage (TypeAliasDeclaration)
lib/utils.ts → convertToUIMessages (FunctionDeclaration)
lib/utils.ts → getTextFromMessage (FunctionDeclaration)
tests/helpers.ts → generateTestMessage (FunctionDeclaration)
app/(chat)/actions.ts → generateTitleFromUserMessage (FunctionDeclaration)
…
--search <q> — BM25 lexical search for vague queries
When you don't know the exact symbol name — the query an agent actually types — --search
ranks symbols by BM25 lexical relevance over split-identifier tokens (the symbol name,
its file's path segments, feature, and kind), fused with file PageRank so a strong hit in an
important file wins ties. No embeddings, no vector DB; the index is built into map.json.
The same ranker is wired into --any as a rung that fires only when exact file/symbol
matching found nothing, so exact routing is unchanged.
$ node agentmap.mjs --search "auth retry logic"
search "auth retry logic": 3 match
src/authRetry.ts → retryWithBackoff (FunctionDeclaration) [6.83]
…
Stopwords (the, that, of, …) are dropped, so --search "the function that dedupes symbols" works. Also available as the search MCP tool.
--relates <path> — blast radius + transitive relevance
The file's own block (exports / imports / direct dependents) plus a random-walk
relevance list (personalized PageRank on the bidirectional import graph) — the files most
related to the target, transitively, not just its direct importers.
$ node agentmap.mjs --relates lib/db/schema.ts
relates: lib/db/schema.ts (pr 0.073744)
exports (14): user(VariableDeclaration), User(TypeAliasDeclaration), chat(VariableDeclaration), Chat(TypeAliasDeclaration), message(VariableDeclaration), DBMessage(TypeAliasDeclaration), …
imports (0): —
dependents (21): hooks/use-active-chat.tsx, lib/types.ts, lib/utils.ts, components/chat/artifact.tsx, components/chat/message.tsx, lib/db/queries.ts, app/(chat)/api/chat/route.ts, …
related (random-walk relevance):
lib/utils.ts (0.0476)
lib/types.ts (0.0376)
components/chat/artifact.tsx (0.0372)
components/chat/icons.tsx (0.0264)
components/chat/message.tsx (0.0237)
lib/db/queries.ts (0.0225)
app/(chat)/api/chat/route.ts (0.0218)
…
For a file carrying a React Server Components directive prologue, the output adds one more
line — boundary: 'use client' (client component) or boundary: 'use server' (server module/actions)
(rsc: 'client' | 'server' in --json) — right after dependents. This is additive and
optional: repos with no 'use client'/'use server' directives never see the line.
--callers <sym> — compiler-accurate call graph (experimental)
Who actually calls a symbol, resolved by the TypeScript language service (ts-morphfindReferencesAsNodes) — not tree-sitter name-matching. This is symbol-level blast radius:
a type-position mention (typeof foo), a re-export, a bare value reference (const x = foo),
or a same-named private local in another file is a different symbol and is never
mis-attributed. --in <path> disambiguates a name defined in more than one file (exported
definitions win over same-named private locals); results are ranked by caller-file PageRank
and capped.
$ node agentmap.mjs --callers getMessageByErrorCode
callers of getMessageByErrorCode [lib/errors.ts]: 3 call sites
app/(chat)/api/chat/route.ts:88 → POST
lib/db/queries.ts:142 → saveMessage
components/chat/message.tsx:57 → PureMessage
A deliberate deep query: it lazily spins up the TS type-checker (a few seconds on a large
repo) only when invoked — the map build and every other query never pay that cost, and
nothing is persisted. Accurate on statically-resolvable calls; dynamic dispatch, reflection,
and string-keyed access are beyond any static tool. Also available as the callers MCP tool.
--calls <sym> — outgoing call graph (experimental)
The companion to --callers: which in-project symbols a symbol invokes. Each call andnew X() site inside its body is resolved by the type checker (getDefinitionNodes), which
follows an imported / re-exported binding through to the real declaration — so a same-named
local elsewhere is never confused for the imported one. node_modules and TypeScript
built-ins (console.log, Array.map, …) are excluded; dynamic dispatch, computed member
access, and higher-order callees are honestly skipped.
$ node agentmap.mjs --calls extractFacts
extractFacts calls [agentmap.mjs]: 15 in-project targets
agentmap.mjs:756 → makeProject (FunctionDeclaration)
agentmap.mjs:944 → rel (VariableDeclaration)
agentmap.mjs:952 → excluded (VariableDeclaration)
…
Same lazy, out-of-band model as --callers (builds a Project only on the query, nothing
persisted). Also the calls MCP tool.
Going transitive — --depth N. Both --callers and --calls accept --depth N
(default 1, max 5) for an N-hop closure: --callers foo --depth 3 is the transitive
blast radius ("everything that reaches foo, up to 3 hops"); --calls foo --depth 3 is
the dependency cone ("everything foo pulls in"). It BFS-traverses the same single warm
Project — no extra build — with cycle detection and node caps so a hub can't explode; each
result is tagged with its depth and a via parent. --depth 1 is the default single-hop
query.
$ node agentmap.mjs --callers leaf --depth 2
callers of leaf [src/chain.ts]: 2 callers within depth 2
src/chain.ts:2 → mid [depth 1]
src/chain.ts:3 → top [depth 2]
--feature <name> — files that make up a feature
Resolves a Next.js app/-router feature to its file set, plus the external files that
depend on it.
$ node agentmap.mjs --feature api
feature "api": 11 files
app/(chat)/api/chat/route.ts
app/(chat)/api/chat/schema.ts
app/(chat)/api/document/route.ts
app/(chat)/api/history/route.ts
app/(chat)/api/messages/route.ts
app/(chat)/api/models/route.ts
app/(chat)/api/suggestions/route.ts
app/(chat)/api/vote/route.ts
app/(auth)/api/auth/guest/route.ts
app/(chat)/api/files/upload/route.ts
app/(chat)/api/chat/[id]/stream/route.ts
external dependents (0): —
--features — list features by size
$ node agentmap.mjs --features
features (4):
api (11 files)
login (1 files)
register (1 files)
chat (1 files)
--hubs — most important files (PageRank)
The files that matter most, ranked by PageRank importance (raw dependent degree shown
alongside).
$ node agentmap.mjs --hubs
agentmap: 154 files (sha 2becdb4)
hubs (PageRank importance):
lib/utils.ts (deg 52, pr 0.105171)
lib/db/schema.ts (deg 21, pr 0.073744)
lib/types.ts (deg 23, pr 0.067589)
components/chat/artifact.tsx (deg 15, pr 0.036882)
components/chat/icons.tsx (deg 27, pr 0.035378)
lib/errors.ts (deg 9, pr 0.032787)
lib/db/queries.ts (deg 14, pr 0.030085)
…
--symbols [N] — top ranked symbols (Aider-style)
The most important individual symbols across the repo, ranked by the identifier graph
(defaults to 30).
$ node agentmap.mjs --symbols 10
top 10 ranked symbols (Aider-style):
0.109902 lib/utils.ts → cn (FunctionDeclaration)
0.036013 lib/types.ts → ChatMessage (TypeAliasDeclaration)
0.025686 components/chat/artifact.tsx → ArtifactKind (TypeAliasDeclaration)
0.022461 lib/errors.ts → ChatbotError (ClassDeclaration)
0.021068 lib/types.ts → CustomUIDataTypes (TypeAliasDeclaration)
0.020872 lib/db/schema.ts → Document (TypeAliasDeclaration)
0.020555 components/ai-elements/suggestion.tsx → Suggestion (VariableDeclaration)
0.020555 lib/db/schema.ts → Suggestion (TypeAliasDeclaration)
0.018124 lib/db/schema.ts → DBMessage (TypeAliasDeclaration)
0.015034 lib/errors.ts → ErrorCode (TypeAliasDeclaration)
--map [--tokens N] [--focus <path>] — token-budgeted ranked digest
The token-budgeted digest (Aider's killer feature): a ranked, files-and-symbols summary
that fits a token budget. Default budget is 8192 (1024 with --focus). --focus <path>
personalizes the ranking toward a file you're working on.
$ node agentmap.mjs --map --tokens 400
# agentmap (154 files, sha 2becdb4) — focus: global, budget ~400 tok
lib/utils.ts:
cn (FunctionDeclaration)
generateUUID (FunctionDeclaration)
lib/types.ts:
ChatMessage (TypeAliasDeclaration)
CustomUIDataTypes (TypeAliasDeclaration)
ChatTools (TypeAliasDeclaration)
Attachment (TypeAliasDeclaration)
components/chat/artifact.tsx:
ArtifactKind (TypeAliasDeclaration)
UIArtifact (TypeAliasDeclaration)
Artifact (VariableDeclaration)
lib/errors.ts:
ChatbotError (ClassDeclaration)
ErrorCode (TypeAliasDeclaration)
lib/db/schema.ts:
Document (TypeAliasDeclaration)
Suggestion (TypeAliasDeclaration)
DBMessage (TypeAliasDeclaration)
# ~387 tokens (14 files shown)
Focused on a working file — the ranking re-centers on what lib/db/queries.ts actually touches:
$ node agentmap.mjs --map --focus lib/db/queries.ts --tokens 350
# agentmap (154 files, sha 2becdb4) — focus: lib/db/queries.ts, budget ~350 tok
lib/utils.ts:
cn (FunctionDeclaration)
generateUUID (FunctionDeclaration)
getDocumentTimestampByIndex (FunctionDeclaration)
fetcher (VariableDeclaration)
getTextFromMessage (FunctionDeclaration)
convertToUIMessages (FunctionDeclaration)
fetchWithErrorHandlers (FunctionDeclaration)
sanitizeText (FunctionDeclaration)
lib/db/schema.ts:
DBMessage (TypeAliasDeclaration)
Suggestion (TypeAliasDeclaration)
Document (TypeAliasDeclaration)
Chat (TypeAliasDeclaration)
User (TypeAliasDeclaration)
chat (VariableDeclaration)
document (VariableDeclaration)
message (VariableDeclaration)
lib/errors.ts:
ChatbotError (ClassDeclaration)
ErrorCode (TypeAliasDeclaration)
# ~324 tokens (8 files shown)
--print — full map as JSON
Dumps the cached map (hubs, features, rankedSymbols, files) as one JSON object —
for piping into other tools. Also includes a top-level fileCount.
$ node agentmap.mjs --print | jq '.hubs[0]'
"lib/utils.ts (deg 52, pr 0.105171)"
--export <mermaid|dot> — visualize the import graph
Serializes the file import graph (nodes = files, edges = imports, top-N by PageRank, with
three light style tiers) as Graphviz DOT or Mermaid — paste straight into
mermaid.live, a GitHub README mermaid block, or dot -Tsvg.--focus <path> scopes to a file's 1-hop neighborhood. It reads the cached map only (no
ts-morph Project), and prints graph text to stdout (so it isn't combined with --json).
$ node agentmap.mjs --export mermaid --focus lib/auth.ts
%% agentmap import graph — 154 files, sha a1b2c3d, focus lib/auth.ts
flowchart TD
classDef hub fill:#d9d9d9,stroke:#333,stroke-width:2px;
n0["lib/auth.ts"]:::hub
…
Global flags
| Flag | Description |
|---|---|
--help / -h |
Print a usage block listing every flag and exit 0. |
--version / -v |
Print the version from package.json and exit 0. |
--json |
Global modifier. When present, every command prints exactly one JSON object to stdout (no prose). Shapes vary per command: --json --hubs → {command,fileCount,sha,hubs:[string]}, --json --find X → {command,query,matches:[{file,name,kind}]}, --json --relates X → {command,file,pagerank,exports,imports,dependents,related}, --json --any X → {command,query,kind,…payload}, etc. Bare --json (no query flag) → {command:"build",fileCount,features,topHub}. |
--no-locals |
Hide non-exported top-level declarations from --find/--any results (shown by default). Never affects --map/--symbols/--hubs ranking. |
--include-dts |
Include .d.ts declaration files in the symbol/ranking pass (excluded by default so generated types don't flood --find/--symbols/--hubs). |
--install-hooks [--dry-run] |
Copy hooks/post-commit into .git/hooks/ (chmod 0755), ensure .claude/agentmap/ is in .gitignore, and auto-wire the Claude Code PreToolUse(Grep) nudge into .claude/settings.json (merge-safe + idempotent). --dry-run previews without writing. Exit 0 on success, stderr + exit 3 on failure. |
--hook-status |
Report whether the post-commit hook, PreToolUse nudge, and .gitignore entry are installed (no writes). |
--doctor |
Read-only harness health report: git/Claude hook wiring, installed skills + Cursor rule freshness vs package.json version, MCP config entries for OpenCode/Antigravity, and map-cache presence/freshness hints. Always exits 0; suggests fix commands (agentmap --install-hooks, --install-skill, --setup-mcp, agentmap) but never runs them. Combine with --json for a structured report. |
--install-skill |
Install skills + always-on docs/hooks per platform (--platform claude|cursor|codex|opencode|gemini|antigravity|copilot|agents|all, default all; --project default, or --global; --dry-run preview). |
--setup-mcp [--dry-run] |
Configure agentmap as an MCP server for OpenCode and the Antigravity IDE (merge-safe). --dry-run previews without writing. |
--mcp |
Start agentmap as a stdio MCP server so non-Claude-Code agents (Cursor, Cline, any MCP client) can query the map. Exposes 11 query tools — any, find, relates, map, hubs, features, feature, symbols, search, callers, calls. |
Exit-code contract: 0 = success / match / help / version; 1 = query returned zero results (--any, --find, --relates, --feature with no match, or --map --focus that resolves to no file — the global digest still prints, with focusResolved:false in --json); 2 = usage error (missing required arg, unknown flag, two commands at once, or a sub-flag without its parent command); 3 = maintenance command failed (--install-hooks, --install-skill, --setup-mcp, --hook-status, --mcp). Any token starting with - that matches no known flag prints an error to stderr and exits 2.
Scope & limitations
Honesty first — this is deliberately a small, sharp tool, not a universal code-graph.
- TS/JS (+ Vue SFC), by design. Built on
ts-morph. Indexes.ts/.tsx/.mts/.cts/.js/.jsx/.mjs/.cjsand the<script>blocks of.vuesingle-file components
(best-effort). No Python, Go, Rust, etc. — if your repo isn't TypeScript/JavaScript, use a
tree-sitter-based tool instead. Want another language?
Vote in #43 — and read
what a non-TS language would actually get
first, because it would not be the same product. - The persisted map is a file-level import graph; the call graph is opt-in. The
cached map's edges come from staticimport/ re-export declarations and the named
symbols crossing them —--relatesanswers the file-level question ("who imports this
module"). Symbol-level, compiler-accurate call-site resolution is available on demand via--callers(who calls a symbol) and--calls(what a symbol invokes) — both experimental,
lazy, out-of-band queries that spin up the type-checker only when invoked and are never
folded into the fast map build. The file-level graph additionally records a React Server
Components client/server boundary tag (from'use client'/'use server'directive
prologues) where present. - Alias & workspace resolution. Resolves
tsconfig/jsconfigpaths,vite/vitest/webpackresolve.alias(string entries, parsed from the AST — the config is never
executed), and pnpm/npm/yarn workspace cross-package imports (@org/pkg→ its source).
A build reportsedgeCoverage(the share of repo-local imports that resolved) and prints a
one-line warning when a repo's imports mostly don't resolve — so a broken/empty map is
never silently framed as success. - Scoping —
.agentmapignore+.d.ts. Generated.d.tsdeclaration files are excluded
from the symbol ranking by default (so a 200-symbol generated types file, ornext-env.d.ts, doesn't flood--find/--symbols/--hubs);--include-dtsrestores
them, and they stay live import-resolution targets either way. A repo-root.agentmapignore
(gitignore-style subset: anchored/, dir/,*globs,#comments) excludes extra paths. - PageRank + symbol ranking are real and implemented (damping 0.85, deterministic
power iteration; personalized variants for--relatesand--map --focus). The symbol
ranking is a faithful port of Aider's identifier-graph approach (credit:
Aider, Apache-2.0). - Feature detection assumes the Next.js
app/router.--feature/--features
derive features from the first real route segment underapp/(orsrc/app/), skipping
route groups(...), dynamic[...], and parallel@...segments. Repos without anapp/directory simply report zero features — every other command still works. - Token counts are estimates (
chars / 4), not a real BPE tokenizer. Treat--map/--tokensbudgets as approximate (±10%). - The PreToolUse hook is Claude Code-specific (it speaks Claude Code's hook JSON). The
post-commit hook is generic git.
What another language would actually get
Published before any of it is built, because the cheapest way to find out you're
being asked for a different product is to describe the product accurately first.
agentmap's accuracy comes from ts-morph — a real TypeScript compiler with a type
checker. Another language would be parsed with tree-sitter: syntax, no types, no
module resolver. That difference decides what each query can honestly return.
| Query | TS / JS today | Another language |
|---|---|---|
--relates (blast radius) |
full | full — ports best; this is the one to lead with |
--search (BM25) |
full | full |
--hubs / --map / --symbols (PageRank) |
full | full |
--print / --export |
full | full — reads the cached map only |
--find |
full | partial — no transitive re-export/barrel chains |
--any |
full | partial |
--callers / --calls |
full | none — refuses, explicitly |
--features / --feature |
Next.js App Router | none |
| incremental rebuild | yes | no — full rebuild every time |
--callers / --calls are ~259 lines of TypeScript language-service calls.
Tree-sitter cannot reproduce them. The options are to refuse loudly or to guess by
name-matching, and name-matching will not ship: a silently mis-wired graph is
worse than no graph, and it would falsify every accuracy claim here.
Two non-TS languages is the honest ceiling for one part-time maintainer — each one
is an ongoing tax, not a one-off. Reasoning, including the arguments against
doing this at all, is in ROADMAP.md Part II.
No telemetry. agentmap makes zero network calls. When an unsupported language
dominates your repo it counts the files locally, prints a one-line pointer to the
vote, and forgets. That count never leaves your machine. Silence it withAGENTMAP_NO_CENSUS=1.
Forks & ports
Two people ported agentmap to another language rather than open an issue, which is
the strongest evidence that the "nobody asked" reading was wrong:
rifanid98/agentmap-go— Godstwn/agentmap-php— PHP / Laravel
Neither is affiliated with this repo and neither is endorsed — listed because
pretending they don't exist would be dishonest about demand. If you maintain one:
upstreaming beats competing, please open an issue.
Contributing
Issues and PRs welcome. High-value directions:
- Retrieval-accuracy eval — done (
EVAL.md,npm run eval). Next: a
type-aware dependents mode (the eval excludes type-only edges to match the value-import
graph) and anapp/-router fixture so--featureretrieval can be scored too. - A real tokenizer behind the
--mapbudget. - Hardening feature detection for non-
app/-router layouts.
Keep the dependency footprint minimal — ts-morph is the only runtime dependency (it bundles
the TypeScript compiler, ~10 MB installed), and keeping it that way is a feature.
License
Yorumlar (0)
Yorum birakmak icin giris yap.
Yorum birakSonuc bulunamadi