{
  "markdown": "# UCN - Universal Code Navigator\n\nSee what code does before you touch it.\n\n[![npm](https://img.shields.io/npm/v/ucn)](https://www.npmjs.com/package/ucn)\n[![tests](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/mleoca/0e10a790e16ab61ddd233e05645e203e/raw/ucn-tests.json)](https://github.com/mleoca/ucn/actions/workflows/ci.yml)\n[![license](https://img.shields.io/npm/l/ucn)](LICENSE)\n\nIf you work with AI Agents, add UCN as a [Skill or MCP tool](#ai-setup). One tool\ngives the agent compact, source-linked answers to caller, impact, and test\nquestions, with uncertainty labeled instead of guessed.\n\nFind symbols, trace callers, check impact, pick the right tests, extract exact\nsource, and spot dead code - from your terminal or your AI agent.\n\nSupports JavaScript, TypeScript, JSX/TSX, Python, Go, Rust, Java, C, C++, C#,\nand HTML inline scripts. All commands, one engine, three ways to use it:\n\n```text\n  Terminal              AI Agents           Agent Skills\n       │                    │                    │\n      CLI                  MCP                 Skill\n       └────────────────────┼────────────────────┘\n                            │\n                     ┌──────┴──────┐\n                     │ UCN Engine  │\n                     │  commands   │\n                     │ tree-sitter │\n                     └─────────────┘\n```\n\nYour tools can already find text. UCN finds *the function* - its definition,\nits callers, its blast radius, its tests - and tells you how sure it is. It\nparses code the way a compiler does (tree-sitter ASTs, not regex) and answers\nthe questions you actually have: who calls this? what breaks if I change it?\nwhich tests should I run? is this dead?\n\nIt's deliberately lightweight:\n\n- **No required background process** - the CLI parses on demand, answers, and\n  exits. MCP stays warm only when you choose to run it.\n- **No HTTP or network stack** - MCP uses a local, dependency-free stdio\n  transport; UCN never opens a port.\n- **No language servers, no compilation** - tree-sitter does the analysis\n  without building the project.\n- **No config** - point it at a directory and ask.\n\nAnd it's built for auditable trust. grep hands you raw matches to sift\nyourself; UCN separates proven edges from possible ones, explains every\nexclusion, and reconciles every occurrence of the name it searched. It never\nturns a zero into a deletion claim. CI re-derives its answers from real\ncompilers and language servers (ts-morph, Pyright, gopls, rust-analyzer,\nJDT LS, Roslyn, clangd) on pinned production repositories. See\n[Answers you can trust](#answers-you-can-trust).\n\n<img src=\"https://raw.githubusercontent.com/mleoca/ucn/main/assets/demo.svg\" alt=\"ucn show on ripgrep: signature, 123 confirmed callers with evidence types, and the ACCOUNT line reconciling all 136 occurrences of the name\" width=\"100%\">\n\n<sub>Real output: one `ucn show` on [ripgrep](https://github.com/BurntSushi/ripgrep) - signature, 123 proven callers with their evidence, and an account of every occurrence of the name. No files opened.</sub>\n\n## Start here\n\n```bash\nnpm install -g ucn                    # Node.js 20+\n\ncd your-project\nucn repo                              # what is this codebase?\nucn find handleRequest                # exact definitions, stable handles\nucn show src/server.ts:42:handleRequest              # the full picture\nucn trace src/server.ts:42:handleRequest --direction=callers\nucn impact src/server.ts:42:handleRequest            # every call site, with evidence\nucn tests src/server.ts:42:handleRequest --depth=3   # which tests to run\n```\n\nThe first command builds an incremental index; the rest reuse it. The cache\nlives outside your project directory, so there's nothing to gitignore.\n\n## Understand code you didn't write\n\nWhat does this function do, who calls it, and how sure is the answer?\n`ucn show` gathers everything useful about one symbol: signature, source,\ncallers, callees, tests, types, dependencies, examples. Project it down to\njust the sections you need:\n\n```text\n$ ucn show detectLanguage --sections=summary,callers,callees --compact\n\nSUMMARY\n───────\ndetectLanguage(filePath: string, projectRoot = null): string|null\n  languages/index.js:420-428  (9 lines)\n  handle: languages/index.js:420:detectLanguage\n  \"Detect language from file path\"\n  async: no  |  side_effects: [none]  |  complexity: branches=1, depth=1\n\nRELATIONSHIPS\n─────────────\nCALLERS — CONFIRMED (51, 30 prod + 21 test):\n  evidence: scope-match (all)\n  [1] cli/index.js:604 [runFileCommand]: const language = detectLanguage(filePath);\n  [7] core/build-worker.js:39 [processFile]: const language = detectLanguage(filePath, rootDir);\n  [17] core/project.js:472 [build]: const language = detectLanguage(filePath, this.root);\n  [34] test/parser-unit.test.js:19: assert.strictEqual(detectLanguage('file.js'), 'javascript');\n  ... 47 more callers\n\nCALLEES (1):\n  evidence: exact-binding (all)\n  [52] detectHeaderLanguage {fs} - core/compilation-database.js:217\nCALLEES — UNVERIFIED (1) — call syntax, receiver/binding unresolved:\n  toLowerCase ×1 — possible-dispatch L422\n\nACCOUNT: \"detectLanguage\" occurs on 79 lines in 20 files: 51 confirmed, 0 unverified,\n  28 non-call (18 import, 1 definition, 3 reference, 6 other-text), 0 other-target, 0 unaccounted\nCONTRACT: literal-name text partition complete; semantic completeness is not claimed\n  (aliases, indirect calls, generated code, and runtime dispatch may exist).\n```\n\n`find` returns stable handles in `file:line:name` form. Pass a handle to any\ncommand to pin the answer to one definition, even when several files or classes\nreuse the same name.\n\n## Follow the execution path\n\nWhat happens when `build()` runs?\n\n```text\n$ ucn trace build --depth=2\n\nbuild\n├── compareNames (core/discovery.js:293) [regular] 3x\n├── recordDiscoveryIssue (core/project.js:346) 2x\n│   └── [unverified] push — method-ambiguous L351\n├── detectProjectPattern (core/discovery.js:760) [utility] 1x\n├── parseGitignore (core/discovery.js:253) [utility] 1x\n│   ├── gitignoreFiles (core/discovery.js:234) [utility] 1x\n│   ├── compareNames (core/discovery.js:293) [utility] 1x (see above)\n│   └── parseGitignoreFile (core/discovery.js:152) [utility] 1x\n├── gitTrackedPaths (core/discovery.js:266) [utility] 1x\n│   ├── hasGitMetadata (core/discovery.js:224) [utility] 1x\n│   └── [unverified] dirname — method-ambiguous L281,L284\n└── ... more callees\n\nCALLEE ACCOUNT: 11 nodes expanded · 210 call sites = 31 confirmed + 33 unverified\n  (25 method-ambiguous, 1 possible-dispatch, 7 uncertain-receiver) + 86 external/builtin + 60 excluded\n```\n\n`trace` walks callees, callers, or callers all the way up to runtime entry\npoints (`--direction=callers --to=entrypoints`). Proven edges form the tree;\ncalls UCN can't prove a receiver for show up as `[unverified]` leaves with a\nreason. The account line reconciles every call site in the expanded tree, so\nunresolved dispatch stays visible and counted instead of quietly vanishing.\n\n## Answers you can trust\n\nUCN doesn't turn every matching name into a semantic claim. Watch it work\nthrough a name with two definitions and a pile of ambiguous method calls:\n\n```text\n$ ucn impact saveCache\n\nImpact analysis for saveCache\ncore/cache.js:610\nNote: Found 2 definitions for \"saveCache\". Using core/cache.js:610. Also in: core/project.js:2380. Use file= to disambiguate.\nCALL SITES: 5 confirmed + 15 unverified\n  Files affected: 3\nBY FILE:\n  core/project.js:2380 [saveCache]: saveCache(cachePath) { return indexCache.saveCache(this, cachePath); }\n  test/prerelease-audit.test.js:1493: saveCache(built, cacheFile);\n  ... (3 more)\nUNVERIFIED CALL SITES (15) — call syntax, no binding/receiver evidence:\n  mcp/server.js:517: try { index.saveCache(); } catch (_) { /* best-effort */ } (possible-dispatch via local receiver)\n  test/cache.test.js:124: index.saveCache(); (possible-dispatch via local receiver)\n  (+13 more)\nACCOUNT: \"saveCache\" occurs on 68 lines in 11 files: 5 confirmed, 15 unverified,\n  12 non-call (3 import, 1 definition, 1 reference, 7 other-text), 36 other-target, 0 unaccounted\nCONTRACT: literal-name text partition complete; semantic completeness is not claimed\n  (aliases, indirect calls, generated code, and runtime dispatch may exist).\n```\n\nUCN sorted all 68 places the name appears:\n\n- **5 confirmed** - call sites it can *prove* resolve to this `saveCache`,\n  via a binding, import, receiver type, qualified path, or same-class evidence.\n- **15 unverified** - real call syntax it refuses to claim. `index.saveCache()`\n  sits on an untyped receiver, so the site stays visible with its reason\n  (`possible-dispatch via local receiver`) instead of being guessed or dropped.\n- **36 other-target** - occurrences that belong to the *other* `saveCache`,\n  kept out of the answer instead of quietly inflating it.\n- **12 non-call** - imports, the definition, comments, strings.\n- **0 unaccounted** - every observed line landed in exactly one bucket.\n\nThat's the payoff: an answer you (or your agent) can audit, instead of an\nopaque match count. A confirmed edge is evidence about the pinned target. An\nunverified edge is a review item with a stated reason. And a clean zero is an\n*observed-text* zero, not a safe-to-delete claim: aliases, generated code,\nreflection, runtime registration, and external consumers can live beyond the\nindexed evidence, and `ucn repo --sections=health --deep` reports exactly those\nblind spots. Even when output is truncated to fit an agent's budget, the\nACCOUNT, CONTRACT, and WARNING lines survive the cut.\n\n### Measured against ground truth\n\nDon't take the tiers on faith. Release gates re-derive UCN's answers from real\ncompilers and language servers on a ten-repository board of pinned production\ncodebases, and publishing is blocked unless they pass. The latest full\nrelease-board run (2026-08-24):\n\n| Repository | Pinned commit | Oracle | Caller precision | Caller recall | Callee prec / recall | Command checks |\n|---|---|---|---:|---:|---:|---:|\n| [preact-signals](https://github.com/preactjs/signals) | [`e0ce9fdf`](https://github.com/preactjs/signals/commit/e0ce9fdf92df7f0ece2c89d44554c39f36dc6882) | ts-morph | 100% | 100% | 100% / 100% | 100% |\n| [httpx](https://github.com/encode/httpx) | [`b5addb64`](https://github.com/encode/httpx/commit/b5addb64f0161ff6bfe94c124ef76f6a1fba5254) | Pyright | 100% | 100% | 100% / 100% | 100% |\n| [cobra](https://github.com/spf13/cobra) | [`ad460ea8`](https://github.com/spf13/cobra/commit/ad460ea8f249db69c943a365fb84f3a59042d54e) | gopls | 100% | 100% | 100% / 100% | 100% |\n| [viper](https://github.com/spf13/viper) | [`528f7416`](https://github.com/spf13/viper/commit/528f7416c4b56a4948673984b190bf8713f0c3c4) | gopls | 100% | 100% | 100% / 100% | 100% |\n| [ripgrep](https://github.com/BurntSushi/ripgrep) | [`82313cf9`](https://github.com/BurntSushi/ripgrep/commit/82313cf95849bfe425109ad9506a52154879b1b1) | rust-analyzer | 100% | 100% | 100% / 100% | 100% |\n| [clap](https://github.com/clap-rs/clap) | [`d3e59a9a`](https://github.com/clap-rs/clap/commit/d3e59a9ab214910b9dad02921b7ef42c6400de9b) | rust-analyzer | 100% | 100% | 100% / 100% | 100% |\n| [javapoet](https://github.com/square/javapoet) | [`b9017a95`](https://github.com/square/javapoet/commit/b9017a9503b76e11b4ad4c1a9f050e2d29112cb0) | JDT LS | 100% | 100% | 100% / 100% | 100% |\n| [newtonsoft-json](https://github.com/JamesNK/Newtonsoft.Json) | [`4f73e743`](https://github.com/JamesNK/Newtonsoft.Json/commit/4f73e74372445108d2c1bda37b36e6f5e43402e0) | Roslyn | 100% | 100% | 100% / 100% | 100% |\n| [cjson](https://github.com/DaveGamble/cJSON) | [`c859b25d`](https://github.com/DaveGamble/cJSON/commit/c859b25da02955fef659d658b8f324b5cde87be3) | clangd | 100% | 100% | 100% / 100% | 100% |\n| [fmt](https://github.com/fmtlib/fmt) | [`e424e3f2`](https://github.com/fmtlib/fmt/commit/e424e3f2e607da02742f73db84873b8084fc714c) | clangd | 100% | 100% | 100% / 100% | 100% |\n\nOn the same run: **zero** in-scope oracle call edges missing from the answer\n(the release gate) on every repository, **zero** false-dead `deadcode` claims\nin the oracle-visible sample, **8,000 / 8,000** cross-command consistency\ncomparisons in agreement, **10 / 10** repositories inside the performance\nbudget (slowest normalized median cold build 17.4K lines/second by wall time,\nworst query p95 83.0 ms, highest peak RSS 908.5 MB), and 3,609 automated tests with no\nfailures or skips. The same gates run in CI (the scheduled\n[Eval workflow](https://github.com/mleoca/ucn/actions/workflows/eval.yml) and\nevery release tag), and `npm run trust:gate` reproduces the release board\nlocally. Pinned sources: [`eval/lib/repos.js`](eval/lib/repos.js).\n\nSemantic runs draw a deterministic, reference-stratified sample of up to 50\ncompiler/LSP symbols per repository, then check caller identity, callee\nidentity, account conservation, review burden, and the public commands `find`,\n`show`, `source`, `trace`, `impact`, `usages`, and `tests` against that same\nexternal population. Unverified precision is reported separately and is\nintentionally much lower on dispatch-heavy code: those entries are review\ncandidates, never confirmed claims.\n\nBeyond the publish gate, a scheduled board re-checks 24 pinned repositories\nacross every supported oracle language (zod, express, hono, zustand, fastify,\nrich, click, attrs, grpc-go, chi, cursive, itertools, gson, jsoup, and\nfriends), plus a rotating fresh-repo arm of codebases the engine was never\ntuned on. Repositories that\nexpose a gap stay on the board; they don't get removed to keep a table pretty.\nThese are measured results on pinned code, not a claim of universal program\nunderstanding or identical performance on every machine.\n\n## Change code without breaking things\n\nWill this change break a call site you've never seen? Check before you edit:\n\n```text\n$ ucn check expandGlob\n\nVerification: expandGlob\n════════════════════════════════════════════════════════════\ncore/discovery.js:314\nexpandGlob (pattern: string, options: number = {}) : string[]\n\nExpected arguments: 1-2\n\nSTATUS: ✓ All calls valid\n  Total calls: 7\n  Valid: 7\n  Mismatches: 0\n  Uncertain: 0\n  Patterns: 4 in try, 4 in callback\n\nACCOUNT: \"expandGlob\" occurs on 14 lines in 6 files: 7 confirmed, 0 unverified,\n  7 non-call (4 import, 1 definition, 2 reference, 0 other-text), 0 other-target, 0 unaccounted\n```\n\nThe `Patterns:` line classifies call-site structure (`inLoop`, `inTry`,\n`inCallback`, `awaited`) so risky sites stand out. Then preview the refactor.\nUCN shows exactly what would need to change and where:\n\n```text\n$ ucn plan expandGlob --rename-to=expandGlobPattern\n\nRefactoring plan: rename\n════════════════════════════════════════════════════════════\ncore/discovery.js:314\n\nSIGNATURE CHANGE:\n  Before: expandGlob (pattern: string, options: number = {}) : string[]\n  After:  expandGlobPattern (pattern: string, options: number = {}) : string[]\n\nCHANGES NEEDED: 12\n  Files affected: 5\n  Definition 1, calls 7, references 0, text dependencies 0, imports 4, exports 0; manual review items 0\n\nBY FILE:\n\ncli/index.js (2 changes)\n  :771 [call]\n    const files = expandGlob(pattern);\n    → Rename to: const files = expandGlobPattern(pattern);\n  :15 [import]\n    const { expandGlob, findProjectRoot } = require('../core/discovery');\n    → Update import: const { expandGlobPattern, findProjectRoot } = require('../core/discovery');\n\n... (more changes in core/discovery.js, core/cache.js, core/project.js, test/integration.test.js)\n```\n\nFor a rename, `plan` closes the change over every relationship the index can\nprove: overload/signature groups, base and override declarations, Rust trait\nslots, Go interface slots and their satisfiers, exact call and value-reference\ntokens, imports/exports, Python `__all__` strings, and module-attribute\nreferences. Accessor renames also follow receiver-proven property reads and\nwrites. It edits exact token or expression spans, so another same-named call\non the same line is not swept up accidentally.\n\nOpen external interfaces, incomplete ownership, unresolved dispatch, or an\ninexact token are marked `needsReview` instead of receiving a synthesized\nedit. Comments and strings in indexed source appear as separate review items\nand are never rewritten automatically; documentation, configuration,\ngenerated files, and unsupported languages get an explicit exact-text search\nhandoff. `plan` previews changes; it does not modify files or replace the\ncompiler and test suite. Before committing, point the same machinery at your\nGit diff:\n\n```bash\nucn impact --staged     # what did I change, and who depends on it?\nucn check --staged      # signature drift, orphaned functions, tests to run\n```\n\n## Pick the right tests\n\nWhich tests actually exercise this function, directly or three hops away?\n\n```text\n$ ucn tests expandGlob --depth=3\n\naffected-tests: expandGlob\n════════════════════════════════════════════════════════════\ncore/discovery.js:314\n1 function changed → 12 functions affected (depth 3)\n\nTest files to run (30):\n\n  test/integration.test.js (links: expandGlob, build, idx, setupProject)\n    L169: const files = expandGlob('**/*.go', { root: tmpDir });  [call]\n  test/prerelease-audit.test.js (links: isCacheStale, runInteractive, build, idx)\n    L39: const index = idx(dir);  [call]\n  ...\n\nSummary: 12 affected → 30 statically linked test files, 5/12 functions linked (42%) · 1 possibly affected (unverified chains)\n```\n\n`tests` reports static call/reference linkage, not runtime coverage. Functions\nreached only through unverified edges are listed separately as *possibly\naffected*, and empty results warn about subprocess tests, reflection, and\nexternal harnesses that may still exercise the target.\n\n## Get the lay of the land\n\nOne command answers \"what is this codebase?\" Here it is on ripgrep:\n\n```text\n$ ucn repo\n\nPROJECT ORIENTATION — ripgrep\n════════════════════════════════════════════════════════════\n100 files · 4755 symbols · language mix by symbols: rust 100%\n\nTOP DIRS (by symbols):\n  crates/core/flags             1510 symbols · 6 file(s)\n  crates/printer/src            677 symbols · 11 file(s)\n  crates/ignore/src             607 symbols · 8 file(s)\n  crates/globset/src            331 symbols · 5 file(s)\n\nHOT (most-called production functions, top 8 of 2238 raw candidates):\n  parse_low_raw — 545 call(s) · crates/core/flags/parse.rs:139\n  SearcherBuilder.build — 123 call(s) · crates/searcher/src/searcher/mod.rs:315\n  Searcher.search_reader — 123 call(s) · crates/searcher/src/searcher/mod.rs:727\n  RegexMatcher.new — 100 call(s) · crates/regex/src/matcher.rs:385\n  ...\n\nENTRY POINTS: 426 — test 421, runtime 5\nTRUST: PARTIAL — 48 glob import(s), 5 unsupported source file(s)  (ucn repo --sections=health --deep for detail)\nSKIPPED SOURCE: 5 file(s) (Shell 4, Ruby 1) — use grep/ripgrep plus a language-native analyzer.\n\nNext: ucn show parse_low_raw · ucn repo --sections=files --detailed · ucn repo --sections=health --deep\n```\n\nSize, layout, hot spots, entry points, and an honest trust line. Note the\n`SKIPPED SOURCE` handoff: when a repo mixes in languages UCN can't parse, it\nsays so and points you at the right tool, instead of presenting a clean-looking\nanswer over a partial index.\n\n## Find dead code you can act on\n\n```text\n$ ucn deadcode --exclude=test        # run on ripgrep\n\nDead code: 3 unused symbol(s)\n\ncrates/globset/src/serde_impl.rs\n  [  38-  42] Glob.deserialize (method)\n  [  70-  74] GlobSet.deserialize (method)\ncrates/matcher/src/lib.rs\n  [ 397- 399] Captures.as_match (method)\n\n33 decorated/annotated symbol(s) hidden (framework-registered). Use --include-decorated to include them.\n\n903 exported symbol(s) excluded from the audit (public API may have external callers). Use --include-exported to audit them.\n\nWARNING: source coverage is incomplete (5 unsupported-language); 17 candidate name(s) found in skipped source were suppressed.\n```\n\nThree claims, and every one is re-checked against rust-analyzer in CI: a\ndefault-audit claim with an oracle-visible reference fails the build. Notice\nwhat it *didn't* claim: exported API that external code may call,\nframework-registered symbols, and anything whose name appears in files UCN\ncouldn't parse. A literal reflection target such as `getattr(obj, \"run\")`\nalso withholds matching member names from deletion candidates; recognized\ndynamic reflection is counted and warned because it cannot be attributed.\n`deadcode` is deliberately a candidate generator. Before\ndeleting, corroborate with `usages`, `impact`, `api`, and your compiler and\ntests.\n\nFor missing-await bugs, `ucn audit-async` lists async calls inside async\nfunctions that lack `await` (JS/TS/Python).\n\n## Map dependencies and API surfaces\n\n```bash\nucn deps src/server.ts --direction=imports --detailed\nucn deps src/server.ts --direction=importers --depth=3\nucn deps --cycles                      # circular imports\nucn api                                # public surface of the project\nucn entrypoints --type=http            # runtime and framework roots\nucn endpoints --bridge --unmatched     # server routes with no client, and vice versa\n```\n\nCycle output separates eager import-time loops from Python chains containing\na function-local/deferred edge. Deferred chains stay visible—they are not\nunconditional import-time cycles, but can still fail if invoked while modules\nare initializing.\n\n`endpoints --bridge` matches server routes to client requests across\nlanguages: Express/Fastify/Koa/NestJS/Next.js, Flask/FastAPI, Spring/JAX-RS,\nGo net/http (Gin/Echo/Chi/Fiber), axum/actix-web, and ASP.NET on the server\nside; fetch/axios, requests/httpx, RestTemplate/WebClient, reqwest, and .NET\nHttpClient on the client side. Exact, partial, and uncertain matches stay in\nseparate tiers.\n\n## Extract and search without opening whole files\n\n```bash\nucn source core/discovery.js:314:expandGlob    # exactly one function\nucn source core/discovery.js --range=314-364   # exactly one range\nucn search '$scope.$apply'                     # literal by default\nucn search 'TODO|FIXME' --regex                # regex is explicit\nucn search --type=call --receiver=client       # structural search\nucn usages expandGlob --include-tests          # every occurrence, classified\n```\n\n`usages` is the escape hatch: the complete literal-name inventory (calls,\ndefinitions, imports, references, comments, strings), for when you want\neverything the text contains, not just what the engine can prove. Regex search runs on an\nRE2-compatible linear-time engine; hostile nested repetition is rejected up\nfront instead of hanging your terminal.\n\n## The 18 commands\n\n| Task | Command |\n|---|---|\n| Repository orientation and health | `repo [--sections=summary,files,stats,health] [--deep]` |\n| Symbol summary and relationships | `show <symbol> [--sections=...]` |\n| Definition lookup | `find <name> [--type=type] [--with-source]` |\n| Complete literal-name inventory | `usages <name>` |\n| Literal, regex, or structural search | `search [term] [--regex] [structural flags]` |\n| Exact source extraction | `source <symbol\\|file:range>` |\n| Call trees: down, up, or to entry points | `trace <symbol> [--direction=...] [--to=entrypoints]` |\n| Symbol or Git-diff impact | `impact [symbol] [--staged]` |\n| Direct or transitively linked tests | `tests <symbol> [--depth=N]` |\n| Signature or pre-commit validation | `check [symbol] [--staged]` |\n| Refactor preview | `plan <symbol> --rename-to=...` |\n| Imports, importers, and cycles | `deps [file] [--direction=...] [--cycles]` |\n| Project or file public API | `api [file]` |\n| Runtime and framework roots | `entrypoints` |\n| Server/client HTTP surface | `endpoints [--bridge]` |\n| Conservative dead-code candidates | `deadcode` |\n| Likely missing awaits | `audit-async` |\n| Stack-trace frame resolution | `stacktrace <text>` |\n\nRun `ucn --help` for every flag. Related modes live behind parameters rather\nthan extra verbs: `trace` handles down, up, and to-entry-points;\n`impact`/`check` handle a symbol or the current Git diff; `show` projects any\nsubset of sections. Flags that don't apply to a command produce an explicit\nwarning instead of silently changing the task.\n\n## Same engine, different transport\n\nCLI, MCP, file mode, project mode, glob mode, and interactive mode resolve\ncommands through the same registry, handlers, index, cache, and formatters:\nsame answers everywhere, different delivery.\n\n- The CLI prints readable text; `--json` returns a stable machine envelope.\n- MCP exposes exactly one tool named `ucn`. Its `command` enum lists the 18\n  tasks, snake_cased where needed (`audit_async`, `project_dir`, `class_name`).\n  A persistent MCP process keeps the index warm across calls.\n- Targeted text answers default to a 10K-character budget, broad ones to 3K,\n  ceiling 100K (`--max-chars` / `max_chars`). Truncation preserves ACCOUNT,\n  CONTRACT, and WARNING lines; JSON is never text-truncated.\n\n```json\n{\n  \"meta\": { \"command\": \"audit-async\", \"canonicalCommand\": \"auditAsync\", \"ok\": true, \"contract\": {} },\n  \"data\": {}\n}\n```\n\nFailures keep the envelope: `meta.ok: false`, `data: null`, and an `error`\nstring, with the command contract when known.\n\n## A cache that stays out of your project\n\nThe incremental index lives under your user cache root, not in the repo:\n`UCN_CACHE_DIR` if set, else `$XDG_CACHE_HOME/ucn`, `~/Library/Caches/ucn`\n(macOS), `%LOCALAPPDATA%/ucn/cache` (Windows), or `~/.cache/ucn`. Canonical\npath hashes keep same-named checkouts separate. `--no-cache` bypasses,\n`--clear-cache` clears the current project, `--clear-cache --all` clears every\nbounded UCN cache. Old in-project `.ucn-cache` directories are migrated out\nautomatically on first use.\n\n## Language coverage\n\nAll parsers feed the same versioned language IR and index path, and sequential\nand worker builds are tested to produce identical symbols, calls, imports, and\nevidence.\n\n- **JavaScript / TypeScript / JSX / TSX** - functions, classes,\n  imports/exports, typed receivers, aliases, callbacks, async flow, framework\n  roots.\n- **Python** - functions, classes, annotations, decorators, imports,\n  comprehensions, context-manager bindings, async flow, framework roots.\n- **Go, Rust, Java** - nominal receivers, methods,\n  inheritance/traits/interfaces, package and path ownership, overload/arity\n  discipline, framework roots.\n- **C** - functions, structs, macros, includes, calls, entry points, API\n  analysis.\n- **C++** - C coverage plus classes, methods, constructors, inheritance,\n  namespaces, overloads, templates, typed field receivers, static array-shape\n  selection, and macro requalification. Conditional macro disagreement stays\n  visible as unverified.\n- **C#** - namespaces, classes/interfaces/records, fields/properties,\n  attributes, declared property/field receiver types, overload and hiding\n  discipline, async flow, top-level programs, .NET stack frames, and\n  ASP.NET/HttpClient endpoints.\n- **HTML** - inline JavaScript and `on*` event handlers.\n\nFor C and C++, a `compile_commands.json` improves header-language,\ninclude-path, and ownership context when available. UCN keeps AST-proven\ndefinitions from recoverable preprocessor branches without claiming which\nbranch a particular build activates.\n\n## Testing and reliability\n\n- **Regression discipline** - every fixed defect gets a focused test.\n- **Surface coverage** - all 18 commands run through CLI text, CLI JSON, and\n  MCP; parity between them is guarded by architecture tests.\n- **External ground truth** - real compilers and language servers adjudicate\n  caller, callee, command, and dead-code claims on pinned repositories\n  ([see the board](#measured-against-ground-truth)).\n- **Release-blocking budgets** - publishing requires 100% in-scope semantic\n  recall, ≥98% confirmed precision, a conserved account for every sample, zero\n  cross-command disagreements, zero default-arm false-dead claims, and the\n  performance gate (≥10K lines/second cold build by wall time and ≥3K by CPU\n  time, query p50 ≤75 ms, p95 ≤250 ms, bounded peak RSS), all on the actual\n  release board.\n\n```bash\nnpm run verify                 # lint + full test suite\nnpm run trust:gate             # the release board: semantic, dead-code, consistency, performance\n```\n\nGate runs write their reports under `eval/reports/` as local run artifacts;\nthe pinned manifest is [`eval/lib/repos.js`](eval/lib/repos.js). Before a tag,\nthe Eval workflow's pre-tag dry run must pass on the actual CI runner.\n\n## AI setup\n\nOne tool, 18 commands, compact source-linked answers that keep their trust\nmetadata even when truncated.\n\n### MCP\n\n```bash\n# Claude Code\nclaude mcp add ucn -- npx -y ucn --mcp\n\n# OpenAI Codex CLI\ncodex mcp add ucn -- npx -y ucn --mcp\n\n# VS Code Copilot\ncode --add-mcp '{\"name\":\"ucn\",\"command\":\"npx\",\"args\":[\"-y\",\"ucn\",\"--mcp\"]}'\n```\n\n<details>\n<summary>Manual MCP configuration</summary>\n\n```json\n{\n  \"mcpServers\": {\n    \"ucn\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"ucn\", \"--mcp\"]\n    }\n  }\n}\n```\n\nVS Code uses `.vscode/mcp.json`:\n\n```json\n{\n  \"servers\": {\n    \"ucn\": {\n      \"type\": \"stdio\",\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"ucn\", \"--mcp\"]\n    }\n  }\n}\n```\n\n</details>\n\n### Agent Skill (no server needed)\n\nmacOS / Linux:\n\n```bash\n# Claude Code\nmkdir -p ~/.claude/skills\ncp -r \"$(npm root -g)/ucn/.claude/skills/ucn\" ~/.claude/skills/\n\n# OpenAI Codex CLI\nmkdir -p ~/.agents/skills\ncp -r \"$(npm root -g)/ucn/.claude/skills/ucn\" ~/.agents/skills/\n```\n\nWindows PowerShell:\n\n```powershell\n$npmRoot = npm root -g\nNew-Item -ItemType Directory -Force \"$env:USERPROFILE\\.claude\\skills\"\nCopy-Item -Recurse \"$npmRoot\\ucn\\.claude\\skills\\ucn\" \"$env:USERPROFILE\\.claude\\skills\\\"\n\nNew-Item -ItemType Directory -Force \"$env:USERPROFILE\\.agents\\skills\"\nCopy-Item -Recurse \"$npmRoot\\ucn\\.claude\\skills\\ucn\" \"$env:USERPROFILE\\.agents\\skills\\\"\n```\n\nThe skill teaches an agent how to orient, pin symbols, choose the smallest\nuseful command, interpret the evidence tiers, and recover from incomplete\nanswers. It's guidance over the same engine, not a second implementation.\n\n## Limitations\n\n- Static, single-project analysis - dependencies like `node_modules` and\n  `site-packages` aren't indexed, and nothing is executed.\n- Reflection, generated code, runtime registration, dynamic property access,\n  and external consumers can be invisible. UCN reports these blind spots\n  (`repo --sections=health --deep`) rather than pretending they don't exist.\n- Interface, trait, template, overload, and untyped-receiver dispatch may stay\n  in the UNVERIFIED tier with a reason instead of being guessed. When\n  same-name definitions compete, `show` lists their stable handles once so\n  agents can see exactly what needs disambiguation.\n- C/C++ analysis doesn't run the preprocessor or compiler; build-specific\n  branches, advanced templates, and macro expansion can remain unresolved. C#\n  analysis doesn't run Roslyn; source generators and external assembly\n  semantics stay outside the index.\n- HTML has regression coverage but no compiler/LSP real-repository oracle.\n- Large repos take a few seconds on the first query, then use the cache.\n\nIf a decision needs compiler completeness or runtime truth, use the compiler,\nthe type checker, the test runner, or a profiler. Those are different tools\nfor different jobs. UCN's job is getting you to the right code fast, with\nanswers you can audit.\n\n---\n\nMIT\n",
  "bytes": 31333,
  "sha": "cff8565c7d82a9887541680c81e5fe9326dfbd3a12eae8fbc2cd7eacf1d9de0c",
  "repo_slug": "mleoca/ucn",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_mleoca_ucn_c74ad612/readme"
}