From cdf38ac45d46f0cb8407ba89102aabec01ef5e2d Mon Sep 17 00:00:00 2001 From: Jordan Coin Jackson Date: Fri, 11 Sep 2026 23:13:10 -0400 Subject: [PATCH] docs: README leads with the agent's first minute; fix collide overclaim; pluralize counts - README: install, setup, mcp, then the three answers with real output and the coverage line first. Peers section names sem, serena, codebase-memory-mcp, zvec-grep and states codemap's difference. - collide help: merge queues do test queued PRs together; collide names the pairs worth building before they reach the queue. - hooks: 1 file / 1 importer instead of 1 files / 1 importers. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01NRaBgKRAZMX9hjbkkefA7T --- README.md | 66 ++++++++++++++++++++++++++++++++++++++++++++-------- cmd/hooks.go | 25 ++++++++++++++++---- collide.go | 5 ++-- 3 files changed, 79 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index c9e0155..f6ebab4 100644 --- a/README.md +++ b/README.md @@ -10,26 +10,68 @@ ![codemap screenshot](assets/codemap.png) +## Your agent's first minute + +```bash +brew tap JordanCoin/tap && brew install codemap # one static binary +cd your-repo && codemap setup # hooks + MCP for Claude Code and Codex +codemap mcp # stdio MCP server for any other client +``` + +After `codemap setup`, the agent gets three answers it cannot get from the source text, at session start, before an edit, and on request. + +**Where things are.** `codemap .` + +``` +╭────────────────────────────── codemap ──────────────────────────────╮ +│ Files: 289 | Size: 2.3MB │ +│ Top Extensions: .go (227), .yml (35), .md (23), .sh (2), .ps1 (1) │ +╰─────────────────────────────────────────────────────────────────────╯ +codemap +├── analysis/ (2 files, 3.6KB, all .go) +├── cmd/ (47 files, 463.2KB, all .go) +├── config/ (2 files, 23.2KB, all .go) +... +``` + +**Who depends on this.** `codemap --importers config/config.go` + +``` +⚠️ HUB FILE: config/config.go + Imported by 40 files - changes have wide impact! + + Dependents: + • blast_radius.go + • cmd/config.go + ... and 38 more +Coverage: complete +``` + +**Where is the code that does X.** `codemap find "hub importers"` + +``` +main.go + matched: resolveImportersInvocation, buildImportersReport, runImportersMode + importers: 0 +Coverage: complete +``` + +Ranked by path and symbol match, each hit tagged with its importer count. Lexical only, and it says so. + +**And the one line every answer carries.** Every dependency answer reports a coverage status: `complete`, `partial`, or `unavailable`, with the source that could not be trusted. A partial graph never reads as a complete one, so "nothing imports this" and "I couldn't tell" are different answers. + ## What it's for -An agent reading your repo can see what a file *says*. It can't cheaply see what depends on that file — that answer lives in `go.mod`, Cargo workspace membership, `package.json` `exports` maps, and `tsconfig` path aliases, not in the source text. +An agent reading your repo can see what a file *says*. It can't cheaply see what depends on that file. That answer lives in `go.mod`, Cargo workspace membership, `package.json` `exports` maps, and `tsconfig` path aliases, not in the source text. codemap computes three things: | | | |---|---| | **Orientation** | A structure map with the most-imported files called out. Cheap cold start, useful when an agent has no memory of the last hour. | -| **Dependency graph** | Imports resolved through each ecosystem's real rules — not string matching. | +| **Dependency graph** | Imports resolved through each ecosystem's real rules, not string matching. | | **Blast radius** | Who breaks if you change this file. | -And one thing that matters more than any of them: **it tells you when it doesn't know.** Every dependency answer carries a coverage status, so a partial graph never reads as a complete one. - -```bash -codemap . # structure + hubs -codemap --importers path/to/file # who depends on this -codemap --diff # what changed vs main -``` - ## Install ```bash @@ -479,6 +521,10 @@ Next: - [ ] Community skill registry (`codemap skill add `) - [ ] Enhanced analysis (entry points, key types) +## Peers + +[sem](https://github.com/Ataraxy-Labs/sem) does symbol-level impact analysis. [serena](https://github.com/oraios/serena) and [codebase-memory-mcp](https://github.com/DeusData/codebase-memory-mcp) are broader MCP servers with semantic retrieval, and [zvec-grep](https://github.com/zvec-ai/zvec-grep) is hybrid search. codemap's difference: imports resolved through each ecosystem's real rules, a coverage status on every answer, and hub warnings before an edit. + ## Contributing Fork → branch → commit → PR. See [CONTRIBUTING.md](CONTRIBUTING.md) before adding a new language. diff --git a/cmd/hooks.go b/cmd/hooks.go index f648ce5..13d8c86 100644 --- a/cmd/hooks.go +++ b/cmd/hooks.go @@ -469,7 +469,7 @@ func hookSessionStart(root string) error { break } importers := len(info.Importers[hub]) - fmt.Printf(" ⚠️ HUB FILE: %s (imported by %d files)\n", hub, importers) + fmt.Printf(" ⚠️ HUB FILE: %s (imported by %s)\n", hub, filesText(importers)) } } else if shouldSkipHubAnalysis(fileCount, fileCountKnown) { fmt.Printf("ℹ️ Hub analysis skipped for large repo (%d files)\n", fileCount) @@ -915,9 +915,9 @@ func hookPromptSubmit(root string) error { for _, file := range filesMentioned { if importers := info.Importers[file]; len(importers) > 0 { if scanner.CountHubImporters(importers) >= scanner.HubThreshold { - output = append(output, fmt.Sprintf(" ⚠️ %s is a HUB (imported by %d files)", file, len(importers))) + output = append(output, fmt.Sprintf(" ⚠️ %s is a HUB (imported by %s)", file, filesText(len(importers)))) } else { - output = append(output, fmt.Sprintf(" 📍 %s (imported by %d files)", file, len(importers))) + output = append(output, fmt.Sprintf(" 📍 %s (imported by %s)", file, filesText(len(importers)))) } } } @@ -1084,9 +1084,9 @@ func planCodemapNextSteps(intent TaskIntent, info *hubInfo) []codemapNextStep { reason := "check callers before editing" switch { case hubImporterCount >= scanner.HubThreshold: - reason = fmt.Sprintf("check blast radius before editing this hub (%d importers)", importerCount) + reason = fmt.Sprintf("check blast radius before editing this hub (%s)", importersNoun(importerCount)) case importerCount > 0: - reason = fmt.Sprintf("check callers before editing (%d importers)", importerCount) + reason = fmt.Sprintf("check callers before editing (%s)", importersNoun(importerCount)) } add("codemap --importers "+shellQuoteIfNeeded(primaryFile), reason) if hubImporterCount >= scanner.HubThreshold { @@ -2322,3 +2322,18 @@ func indexOf(slice []string, val string) int { } return len(slice) } + +// filesText and importersNoun keep counts grammatical: "1 file", "2 files". +func filesText(n int) string { + if n == 1 { + return "1 file" + } + return fmt.Sprintf("%d files", n) +} + +func importersNoun(n int) string { + if n == 1 { + return "1 importer" + } + return fmt.Sprintf("%d importers", n) +} diff --git a/collide.go b/collide.go index 3fd42e6..d1d58ea 100644 --- a/collide.go +++ b/collide.go @@ -270,8 +270,9 @@ func printCollideUsage(fs *flag.FlagSet) { fmt.Fprintln(os.Stderr, "Usage: codemap collide [options]") fmt.Fprintln(os.Stderr) fmt.Fprintln(os.Stderr, "Rank open pull requests by the merge-order hazard they share: which pairs") - fmt.Fprintln(os.Stderr, "change the same files, weighted by how many files import them. CI cannot see") - fmt.Fprintln(os.Stderr, "this, because every PR is built against main and never against its siblings.") + fmt.Fprintln(os.Stderr, "change the same files, weighted by how many files import them. It names the") + fmt.Fprintln(os.Stderr, "pairs worth building together before they reach a merge queue, with the shared") + fmt.Fprintln(os.Stderr, "files and importer counts, so the queue's first failure is not the first warning.") fmt.Fprintln(os.Stderr) fmt.Fprintln(os.Stderr, "Weights are labelled with the granularity they were measured at. A language") fmt.Fprintln(os.Stderr, "whose imports name files (TypeScript, JavaScript, Python) reports importers of")