Skip to content

feat(cli): codemap validate / context / --performance, four new query recipes, friendlier no-DB error#23

Merged
SutuSebastian merged 12 commits intomainfrom
feat/agent-friendly-cli
Apr 27, 2026
Merged

feat(cli): codemap validate / context / --performance, four new query recipes, friendlier no-DB error#23
SutuSebastian merged 12 commits intomainfrom
feat/agent-friendly-cli

Conversation

@SutuSebastian
Copy link
Copy Markdown
Contributor

@SutuSebastian SutuSebastian commented Apr 27, 2026

Summary

Agent-friendly CLI surface, four new bundled query recipes, and a JSDoc/lint pass over the public type surface. No schema change → ships as patch (0.2.3).

This PR is the result of a competitive scan of fallow-rs/fallow, AZidan/codemap, and JordanCoin/codemap — full audit and adopt/watch/pass list saved as docs/research/competitive-scan-2026-04.md.

What lands

New CLI commands & flags

  • codemap validate [--json] [paths...] — diffs disk SHA-256 against files.content_hash. Statuses: stale | missing | unindexed. Exits 1 on any drift (git-status semantics).
  • codemap context [--compact] [--for "<intent>"] — stable JSON envelope (project metadata, top hubs, recent markers, recipe catalog). --for runs lightweight intent classification (refactor / debug / test / feature / explore / other) and returns matched recipe ids plus a hint.
  • codemap --performance — per-phase timing (collect / parse / insert / index_create) plus top-10 slowest files by parse time during full rebuilds.
  • -r short alias for codemap query --recipe; --help reorganized with sectioned flags, dynamic recipe-id padding, and examples for both forms.
  • Friendlier no-.codemap.db errorno such table: <X> rewrites to an actionable hint pointing at codemap / codemap --full.

New bundled query recipes (codemap query -r <id>)

  • deprecated-symbols — symbols whose JSDoc contains @deprecated
  • visibility-tags@internal / @private / @alpha / @beta
  • files-hashes — every indexed file with content_hash (powers codemap validate)
  • barrel-files — top files by export count

Public type surface

  • New IndexPerformanceReport; IndexRunStats.performance? field.
  • Per-field JSDoc on IndexResult, IndexRunStats, IndexPerformanceReport, IndexTableStats, ResolvedCodemapConfig.
  • Interface-level JSDoc on every db.ts row interface (FileRow, SymbolRow, …, TypeMemberRow) with cross-links to docs/architecture.md § Schema.
  • Per-field JSDoc on ParsedFile (clarifies error vs parseError, category semantics, CSS-only fields).
  • @param/@returns on getAdapterForExtension.

Documentation

  • README leads with a "What you get" Grep/Read vs Codemap capability table and a "Daily commands" stripe.
  • docs/why-codemap.md adds a "What Codemap is not" anti-pitch section and a scenario-keyed token-savings table replacing the earlier "very large vs ~5K" hand-wave.

Lint baseline

Stricter .oxlintrc.json: prefer-const, import/consistent-type-specifier-style, typescript/consistent-type-definitions (interface), no-confusing-non-null-assertion, no-unnecessary-{boolean-literal-compare,template-expression,type-assertion}, prefer-{includes,nullish-coalescing,optional-chain}, unicorn/switch-case-braces. fixtures/ ignored so hand-crafted parser corpora aren't auto-mutated.

Out of scope (deferred)

  • MCP server (codemap mcp)
  • HTTP API (codemap serve)
  • Project-local recipes / skills override
  • Watch mode
  • Remote-repo support — explicitly dropped after discussion (demoware, doesn't fit our SQL-index thesis)

Commit layout (5 clean commits)

  1. chore(deps) — routine dep bumps (independent of feature work)
  2. docs — anti-pitch, token table, capability table, research scan, lessons
  3. chore(lint) — stricter oxlint baseline + ignore fixtures
  4. feat(query) — four new recipes + -r alias + cleaner help
  5. feat(cli)validate / context / --performance / friendlier error / JSDoc round / lint auto-fixes / changeset

Test plan

  • bun run check (build + format:check + lint + tests + typecheck) → green
  • bun scripts/query-golden.ts → 19/19 scenarios pass (4 new)
  • bun test → 182/182 (23 new across cmd-query / cmd-validate / cmd-context)
  • Smoke: bun src/index.ts validate --json flags stale files correctly; exit code 1 on drift
  • Smoke: bun src/index.ts context --compact --for "refactor the parser" returns intent block
  • Smoke: bun src/index.ts --full --performance prints per-phase + top-10
  • Smoke: bun src/index.ts query -r index-summary works as alias
  • Smoke: friendlier no-DB error verified in a fresh /tmp working dir
  • Reviewer eyeball: changeset wording, README capability-table rows, why-codemap anti-pitch tone

Summary by CodeRabbit

  • New Features

    • Added codemap validate (JSON output option), codemap context (stable JSON envelope, --for intent), --performance rebuild reporting, -r alias for --recipe, and four built-in recipes (deprecated-symbols, visibility-tags, files-hashes, barrel-files)
  • Documentation

    • Expanded README and docs with examples, daily commands, scope clarifications, and refreshed API/type JSDoc
  • Bug Fixes

    • Enhanced "no such table/column" hints suggesting codemap/codemap --full
  • Chores

    • Dependency bumps and stricter lint rules enforced

Routine bumps caught by lockfile drift; no functional changes.
… commands

- why-codemap.md: add "What Codemap is not" section (anti-pitch — preempts
  "is this an LSP / agent / smart tool?" reading); replace narrative
  token-savings text with scenario-keyed rows (single lookup → 50-turn
  session) backed by a methodology footnote pointing at bun run benchmark:query
- README.md: add "What you get" Grep/Read vs Codemap capability table near
  the top; add a "Daily commands" stripe and a "version-matched Agent Skill"
  packaging line in the CLI section
- docs/research/competitive-scan-2026-04.md: capture the audit of fallow,
  AZidan/codemap, and JordanCoin/codemap that drove the messaging changes
- .agents/lessons.md: add bump-policy lesson (patch by default for 0.x;
  reserve minor for schema-breaking changes; strict SemVer post-1.0)
Add the import plugin and 11 stricter rules: prefer-const, type-import
hoisting (consistent-type-specifier-style: prefer-top-level), interface
preference for object types, no-confusing-non-null-assertion,
no-unnecessary-{boolean-literal-compare,template-expression,type-assertion},
prefer-{includes,nullish-coalescing,optional-chain}, and
unicorn/switch-case-braces.

Add fixtures/ to ignorePatterns so hand-crafted parser test corpora are
never auto-mutated (prevents golden churn — discovered when an auto-fix
on fixtures/minimal/src/consumer.ts split a mixed import and broke the
imports-consumer-alias / files-hashes / index-summary scenarios).

Source-side auto-fixes from these rules ship with the feature commits
that follow.
Recipes (all parameterless SQL on the existing schema):
- deprecated-symbols  — symbols whose JSDoc contains @deprecated; lets
  agents flag callers of soon-to-be-removed APIs
- visibility-tags     — symbols tagged @internal / @Private / @Alpha / @beta
- files-hashes        — every indexed file with content_hash; powers the
  forthcoming `codemap validate` CLI
- barrel-files        — top files by export count (public-API hubs)

CLI:
- -r is now a short alias for --recipe (e.g. `codemap query -r fan-out`)
- --help is reorganized: sectioned flags, dynamic recipe-id padding,
  examples for both --recipe and -r forms

Fixtures:
- @deprecated and @internal JSDoc added to fixtures/minimal/src/utils/date.ts
  to give the new recipes real rows to assert on
- 4 new golden scenarios + index-summary refresh (symbols 8 → 9)
…er no-DB error; JSDoc the public type surface

CLI commands and flags
- codemap validate [--json] [paths...] — diffs disk SHA-256 against
  files.content_hash; statuses: stale | missing | unindexed; exits 1 on
  any drift (git-status semantics) so agents can branch on $?
- codemap context [--compact] [--for "<intent>"] — stable JSON envelope
  (project metadata, top hubs, recent markers, recipe catalog). --for runs
  lightweight intent classification (refactor / debug / test / feature /
  explore / other) and returns matched recipe ids plus a hint
- codemap --performance — per-phase breakdown
  (collect / parse / insert / index_create) plus top-10 slowest files by
  parse time during full rebuild; surfaces pathological inputs
- Friendlier no-.codemap.db error — `no such table: <X>` rewrites to an
  actionable hint pointing at `codemap` / `codemap --full`, on both the
  JSON and human paths
- bootstrap.ts whitelists the new subcommands and flag

Public type surface (visible in dist/index.d.mts via the existing index re-exports)
- New IndexPerformanceReport; IndexRunStats.performance? field
- Per-field JSDoc on IndexResult, IndexRunStats, IndexPerformanceReport,
  IndexTableStats (snake_case key note), ResolvedCodemapConfig
- Interface-level JSDoc on every db.ts row interface (FileRow, SymbolRow,
  ImportRow, ExportRow, ComponentRow, DependencyRow, MarkerRow,
  CssVariableRow, CssClassRow, CssKeyframeRow, CallRow, TypeMemberRow)
  with cross-links to docs/architecture.md § Schema as the single source
- Per-field JSDoc on ParsedFile (clarifies error vs parseError, category
  semantics, CSS-only fields, cssImportSources main-thread conversion)
- @param/@returns on getAdapterForExtension

Implementation plumbing
- ParsedFile gains optional parseMs?, populated by parse-worker-core.ts
- RunIndexOptions.performance threads through index-engine.ts and run-index.ts
- index-engine.ts times collect / parse / insert / createIndexes phases when
  the flag is on; bottom-of-summary block prints the breakdown plus the
  slowest_files list

Auto-fixes from the new lint baseline
- import type hoisting (consistent-type-specifier-style: prefer-top-level)
- type X = {...} → interface X {...} for object shapes (ValidateRow,
  ValidateOpts, ContextEnvelope, ContextOpts)
- switch case braces in src/parser.ts (12 keyword-mapping cases) and
  src/agents-init.ts

Tests
- 9 new tests for cmd-validate (parse + computeValidateRows: stale, missing,
  unindexed, dedup, sort)
- 14 new tests for cmd-context (parse + classifyIntent: 6 categories + fallback)
- 2 new cases on cmd-query for -r

Changeset entered as patch (matches 0.x precedent for additive changes;
schema unchanged).
@SutuSebastian SutuSebastian added documentation Improvements or additions to documentation enhancement New feature or request labels Apr 27, 2026
@SutuSebastian SutuSebastian self-assigned this Apr 27, 2026
@SutuSebastian SutuSebastian added documentation Improvements or additions to documentation enhancement New feature or request labels Apr 27, 2026
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 27, 2026

🦋 Changeset detected

Latest commit: 22939c2

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@stainless-code/codemap Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 27, 2026

Warning

Rate limit exceeded

@SutuSebastian has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 4 minutes and 51 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1142bb8f-cd96-4bd1-89a7-1ce44f2068c8

📥 Commits

Reviewing files that changed from the base of the PR and between 0fafbff and 22939c2.

📒 Files selected for processing (18)
  • .agents/rules/docs-governance.md
  • .changeset/agent-friendly-cli-recipes.md
  • .cursor/rules/docs-governance.mdc
  • docs/README.md
  • docs/architecture.md
  • docs/glossary.md
  • docs/golden-queries.md
  • docs/plans/.gitkeep
  • docs/research/competitive-scan-2026-04.md
  • docs/roadmap.md
  • docs/why-codemap.md
  • src/adapters/builtin.ts
  • src/cli/cmd-context.test.ts
  • src/cli/cmd-context.ts
  • src/cli/cmd-validate.ts
  • src/config.ts
  • src/db.ts
  • src/parsed-types.ts
📝 Walkthrough

Walkthrough

Adds two CLI commands (validate, context) with tests and JSON outputs, instruments and reports index performance, introduces four bundled query recipes and golden fixtures, tightens lint rules and dependency versions, expands documentation and JSDoc, and refactors several imports/type declarations.

Changes

Cohort / File(s) Summary
New CLI commands & tests
src/cli/cmd-validate.ts, src/cli/cmd-validate.test.ts, src/cli/cmd-context.ts, src/cli/cmd-context.test.ts
Implements codemap validate (hash-drift checks, JSON output) and codemap context (stable JSON envelope, intent classification); adds parsing, runtime wiring, and tests.
CLI integration & help
src/cli/main.ts, src/cli/bootstrap.ts, src/cli/cmd-index.ts, src/cli/cmd-query.ts, src/cli/cmd-query.test.ts
Wires new subcommands into main dispatch, documents --performance, adds -r alias for --recipe, improves help formatting and error messages.
Query recipes & fixtures
src/cli/query-recipes.ts, fixtures/golden/minimal/*, fixtures/golden/scenarios.json
Adds four recipes (deprecated-symbols, visibility-tags, files-hashes, barrel-files) and corresponding golden fixtures/scenarios for testing.
Indexing performance & types
src/application/index-engine.ts, src/application/run-index.ts, src/application/types.ts
Adds optional performance collection, per-phase timers, top-10 slowest files capture, IndexPerformanceReport type, and exposes performance in index results; enriches index-run stats types.
Parse instrumentation & worker
src/parse-worker-core.ts, src/parsed-types.ts
Records per-file parseMs timing and clarifies ParsedFile JSDoc semantics.
DB, sqlite, and row docs
src/db.ts, src/sqlite-db.ts
Refactors type-only imports and adds detailed JSDoc for exported row interfaces and internal sqlite interface conversion to interface.
Minor refactors & imports
src/api.ts, src/benchmark.ts, scripts/query-golden.ts, scripts/benchmark-query-output.ts, src/agents-init.ts, src/adapters/builtin.ts, src/parser.ts
Convert several imports to import type, wrap switch-case bodies in blocks, add JSDoc, and small formatting/refactor changes.
Configuration, linting & deps
.oxlintrc.json, package.json, .changeset/agent-friendly-cli-recipes.md
Tightens ESLint/TypeScript/unicorn rules, ignores fixtures in lint, bumps multiple deps, and adds a changeset documenting CLI and API updates.
Docs & research
.agents/lessons.md, README.md, docs/why-codemap.md, docs/research/competitive-scan-2026-04.md
Adds 0.x versioning guidance, expands README with daily commands and capability mapping, clarifies scope ("What Codemap is not"), and adds competitive-scan research with proposals.
Fixtures & example code
fixtures/minimal/src/utils/date.ts
Marks now() as @deprecated and adds export function _epochSeconds(): number for fixture coverage.

Sequence Diagrams

sequenceDiagram
    participant User as CLI User
    participant ValidateCmd as Validate Command
    participant DB as Codemap Database
    participant FileSystem as File System
    participant Output as Output Handler

    User->>ValidateCmd: codemap validate [--json] [paths]
    ValidateCmd->>ValidateCmd: parseValidateRest() → options
    ValidateCmd->>DB: open (read-only) & query files table
    DB-->>ValidateCmd: indexed files + hashes
    ValidateCmd->>FileSystem: resolve/check existence (explicit or all indexed)
    FileSystem-->>ValidateCmd: file presence / content
    ValidateCmd->>ValidateCmd: computeValidateRows() (compare hashes)
    alt Any stale/missing/unindexed
        ValidateCmd->>Output: print JSON array or human rows
        Output-->>User: validation report
        ValidateCmd->>ValidateCmd: set exitCode = 1
    else All clean
        ValidateCmd->>Output: print success
        Output-->>User: success
    end
Loading
sequenceDiagram
    participant User as CLI User
    participant ContextCmd as Context Command
    participant Codemap as Codemap Initializer
    participant DB as Codemap Database
    participant Envelope as Envelope Builder
    participant Output as Output Handler

    User->>ContextCmd: codemap context [--compact] [--for intent]
    ContextCmd->>ContextCmd: parseContextRest() → options
    ContextCmd->>Codemap: loadUserConfig & initCodemap
    Codemap-->>ContextCmd: runtime initialized
    ContextCmd->>DB: open database
    DB-->>ContextCmd: ready
    ContextCmd->>Envelope: buildContextEnvelope(db, root, opts)
    Envelope->>DB: query metadata (files, languages, recipes, hubs)
    DB-->>Envelope: metadata
    alt intent specified
        Envelope->>Envelope: classifyIntent() → matched recipes & hint
    end
    ContextCmd->>Output: print JSON envelope
    Output-->>User: context JSON
Loading
sequenceDiagram
    participant CLI as CLI Runner
    participant IndexEngine as Index Engine
    participant Parser as Parse Worker
    participant FileSystem as File System

    CLI->>IndexEngine: indexFiles({performance: true, ...})
    IndexEngine->>IndexEngine: start collectMs timer
    IndexEngine->>FileSystem: collectFiles()
    FileSystem-->>IndexEngine: file list
    IndexEngine->>IndexEngine: record collectMs
    IndexEngine->>Parser: parse each file (measure parseMs)
    Parser->>FileSystem: read file
    FileSystem-->>Parser: content
    Parser-->>IndexEngine: ParsedFile {parseMs,...}
    IndexEngine->>IndexEngine: track slowest 10 files, record insert/index times
    IndexEngine-->>CLI: IndexRunStats {performance: report, ...}
    alt quiet=false
        IndexEngine->>CLI: print performance breakdown + slowest files
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Poem

🐰🌿 New commands hop in, validate and context sing,
Timers keep the tempo while golden fixtures spring.
Recipes bloom in SQL fields, docs and lint stand tight,
I nibble on the index and cheer at the new light. 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 48.84% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main changes: new CLI commands (validate, context), performance flag, query recipes, and improved error handling.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/agent-friendly-cli

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (8)
src/db.ts (1)

250-620: JSDoc additions on row interfaces are accurate and useful — small consistency nit on nullability.

The new doc blocks correctly cross-link to docs/architecture.md sections and document the deprecated-symbols / visibility-tags / files-hashes recipe touchpoints.

Minor (pre-existing, not introduced here, flagging while you're in the area): FileRow.size, line_count, language, last_modified, indexed_at are typed as non-nullable, but the files schema (lines 29-37) only declares path and content_hash as NOT NULL — a row read back via query<FileRow>(...) could legally surface null for any of those columns. If you ever rely on the types at read time (vs. at insert), consider tightening the schema with NOT NULL to match, or widening the interface to … | null. Out of scope for this PR; no need to address now.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/db.ts` around lines 250 - 620, The FileRow interface declares fields
(size, line_count, language, last_modified, indexed_at) as non-nullable but the
underlying files table only guarantees path and content_hash NOT NULL; to fix,
either update the SQL schema to mark those columns NOT NULL to match FileRow
(modify the CREATE TABLE for files) or relax the TypeScript model by making
those properties nullable (e.g., size: number | null, line_count: number | null,
language: string | null, last_modified: number | null, indexed_at: number |
null) so reads via query<FileRow>(...) are type-safe; locate the TypeScript
interface FileRow and the DB schema definition for files to apply the change
consistently.
src/cli/cmd-index.ts (1)

36-41: LGTM — flag wiring is straightforward.

Note: --performance is intentionally only honored in full/incremental modes (not --files), which aligns with the PR objective of per-phase timing during rebuilds. Minor nit: the local name performance shadows the global performance API; it's harmless here since performance.now() isn't used in this scope, but renaming to reportPerformance (or similar) would avoid the shadow.

♻️ Optional rename to avoid shadowing the global
       const fullRebuild = args.includes("--full");
-      const performance = args.includes("--performance");
+      const reportPerformance = args.includes("--performance");
       await runCodemapIndex(db, {
         mode: fullRebuild ? "full" : "incremental",
-        performance,
+        performance: reportPerformance,
       });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/cli/cmd-index.ts` around lines 36 - 41, Local variable named
"performance" shadows the global performance API; rename the local const to
something like reportPerformance to avoid shadowing, update the args check
(const reportPerformance = args.includes("--performance");) and pass it into
runCodemapIndex as the performance property (runCodemapIndex(db, { mode:
fullRebuild ? "full" : "incremental", performance: reportPerformance })),
leaving the external API/prop name "performance" unchanged so runCodemapIndex
keeps its existing signature.
src/api.ts (1)

4-8: Optional: collapse with inline type modifiers.

Splitting into two statements works (and is verbatimModuleSyntax-safe), but the inline type modifier keeps the value+type imports from the same module on one line and is generally easier to keep in sync.

♻️ Proposed change
-import { runCodemapIndex } from "./application/run-index";
-import type { RunIndexOptions } from "./application/run-index";
+import { runCodemapIndex, type RunIndexOptions } from "./application/run-index";
 import type { IndexResult } from "./application/types";
-import { loadUserConfig, resolveCodemapConfig } from "./config";
-import type { CodemapUserConfig } from "./config";
+import {
+  loadUserConfig,
+  resolveCodemapConfig,
+  type CodemapUserConfig,
+} from "./config";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/api.ts` around lines 4 - 8, Combine the separate value and type imports
into single-line imports using inline `type` modifiers so the value and its
types stay together; e.g., import runCodemapIndex and its RunIndexOptions from
"./application/run-index" in one statement, import IndexResult as a type from
"./application/types" inline, and import loadUserConfig, resolveCodemapConfig
together with CodemapUserConfig as an inline type from "./config" to collapse
the multiple import statements into fewer lines while keeping
verbatimModuleSyntax compatibility.
fixtures/golden/scenarios.json (1)

87-91: Consider invoking the files-hashes recipe instead of inlined SQL.

The other three new scenarios (deprecated-symbols, visibility-tags, barrel-files) reference recipes via the recipe field, but files-hashes duplicates the SQL inline. Since the PR introduces files-hashes as a bundled recipe (the one that powers codemap validate), routing the golden scenario through the recipe ensures the recipe SQL itself is exercised and prevents drift between the fixture and the recipe definition.

♻️ Proposed change
   {
     "id": "files-hashes",
     "prompt": "All indexed file paths with language and line count (powers `codemap validate`)",
-    "sql": "SELECT path, language, line_count FROM files ORDER BY path"
+    "recipe": "files-hashes"
   },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@fixtures/golden/scenarios.json` around lines 87 - 91, The golden scenario for
"files-hashes" currently inlines SQL; replace that inline SQL object with a
reference to the bundled recipe by adding a "recipe": "files-hashes" field and
removing the "sql" field so the fixture routes through the recipe (match how
"deprecated-symbols", "visibility-tags", and "barrel-files" use the recipe
field), ensuring the recipe's SQL is exercised and avoids drift from the recipe
definition.
README.md (1)

45-56: Optional: surface the new validate / context commands in Daily commands.

The headline additions in this PR are codemap validate and codemap context, but the new "Daily commands" section doesn't include them. Consider adding one-liner examples here so they show up at the top of the README alongside codemap query.

Suggested addition
 codemap                                                      # incremental index (run once per session)
 codemap query --json --recipe fan-out                        # bundled SQL via recipe id
 codemap query --json "SELECT name, file_path FROM symbols WHERE name = 'foo'"  # ad-hoc SQL
 codemap --files src/a.ts src/b.tsx                           # targeted re-index after edits
+codemap validate --json                                      # detect stale / missing / unindexed files
+codemap context --compact --for "refactor auth"              # JSON envelope + intent-matched recipes
 codemap agents init                                          # scaffold .agents/ rules + skills
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@README.md` around lines 45 - 56, Add one-line examples for the new CLI
commands to the "Daily commands" section: include "codemap validate" and
"codemap context" alongside the existing commands so they appear at the top of
the README; update the list under "Daily commands" to show usage examples for
the commands named codemap validate and codemap context (e.g., a short
description each) so readers see the new headline features next to codemap query
and others.
src/cli/cmd-validate.test.ts (1)

19-23: Optional: avoid duplicating the files table DDL in tests.

The hand-rolled CREATE TABLE files ... STRICT and raw INSERT here couple the test to a snapshot of the production schema. If createSchema (or the columns) evolve, these tests will keep passing while production diverges. Consider using the real schema creation helper (e.g., createSchema(db) from ../db) and a typed insert helper so the validate tests exercise the same shape end users get.

Also applies to: 30-42

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/cli/cmd-validate.test.ts` around lines 19 - 23, Replace the hand-rolled
DDL and raw INSERTs in cmd-validate.test.ts with the production schema helper
and typed insert helper: instead of calling openDb() then running the raw
"CREATE TABLE ... STRICT" DDL, call createSchema(db) (from ../db) after
openDb(), and use the project's typed file insert helper (e.g., insertFile or
similar) to populate rows so the test uses the same column shape as production;
do the same replacement for the other occurrences around lines 30-42, and keep
closeDb(db, { readonly: false }) as-is.
src/cli/cmd-context.ts (2)

91-102: Edge case: --for "" is accepted as a valid intent.

Empty string doesn't start with -- and isn't undefined, so it slips through and gets handed to classifyIntent("") — which falls through to the "other" branch silently. Minor, but a one-line guard (if (v === undefined || v === "" || v.startsWith("--"))) keeps the error symmetric with the help text, which says "intent string in quotes".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/cli/cmd-context.ts` around lines 91 - 102, The "--for" handling currently
accepts an empty quoted string because the guard only checks for undefined or
tokens starting with "--"; update the condition in the parsing branch that
checks the lookahead variable v (used to set intent) to also reject an empty
string (e.g., change the if that returns the error to check v === undefined || v
=== "" || v.startsWith("--")), so that intent is only assigned when v is
non-empty; this keeps the behavior consistent with the help text and prevents
classifyIntent("") from receiving an empty intent.

248-256: --compact doesn't actually compact the JSON.

JSON.stringify(envelope, null, 2) is unconditional, so --compact only drops two fields but still pretty-prints the rest with 2-space indent. For an agent pipeline trying to minimize tokens (the documented motivation), passing null/0 as the indent argument when opts.compact is true would meaningfully shrink the payload.

♻️ Suggested change
-    console.log(JSON.stringify(envelope, null, 2));
+    console.log(
+      opts.compact
+        ? JSON.stringify(envelope)
+        : JSON.stringify(envelope, null, 2),
+    );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/cli/cmd-context.ts` around lines 248 - 256, The output always
pretty-prints the envelope because JSON.stringify(envelope, null, 2) is
unconditional; change the console.log call that prints envelope to respect the
compact flag (opts.compact) by passing no/zero indent when compact is true and
2-space indent otherwise (i.e., use opts.compact to choose the indent argument
for JSON.stringify on the envelope); update the call that logs the successful
envelope (symbol: envelope) to use this conditional indent so --compact actually
emits compact JSON.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/cli/cmd-context.ts`:
- Around line 25-30: The field recent_markers is misnamed because the SQL for
recent_markers (the query that selects from the markers table ordered by
file_path ASC, line_number ASC LIMIT 20) has no recency signal; either rename
the field and related help/changelog to something like sample_markers or
top_markers (update the exported property recent_markers, help text, and
changeset references) or modify the query used by the function that builds
recent_markers to join markers -> files and ORDER BY files.last_modified DESC
(or files.indexed_at DESC) so the data is actually recent; locate the SQL/query
in the code that populates recent_markers and apply one of these two fixes
consistently (including the duplicate places noted around the other reference
lines).

In `@src/cli/cmd-validate.ts`:
- Around line 119-130: Replace the fragile existsSync + readFileSync sequence
with a single guarded read and error-handling around the read; in the block
using indexedHash, remove the existsSync check and instead try to read the file
at abs (using readFileSync or an equivalent) inside a try/catch, on success
compute diskHash = hashContent(fileContents) and compare to indexedHash (push
{path: rel, status: "stale"} if different), and on failure push a non-fatal
status for that file (e.g., {path: rel, status: "missing"} or "unreadable") and
continue; update references to indexedHash, rel, abs, hashContent and rows so
the validation run does not crash on TOCTOU/read errors.

---

Nitpick comments:
In `@fixtures/golden/scenarios.json`:
- Around line 87-91: The golden scenario for "files-hashes" currently inlines
SQL; replace that inline SQL object with a reference to the bundled recipe by
adding a "recipe": "files-hashes" field and removing the "sql" field so the
fixture routes through the recipe (match how "deprecated-symbols",
"visibility-tags", and "barrel-files" use the recipe field), ensuring the
recipe's SQL is exercised and avoids drift from the recipe definition.

In `@README.md`:
- Around line 45-56: Add one-line examples for the new CLI commands to the
"Daily commands" section: include "codemap validate" and "codemap context"
alongside the existing commands so they appear at the top of the README; update
the list under "Daily commands" to show usage examples for the commands named
codemap validate and codemap context (e.g., a short description each) so readers
see the new headline features next to codemap query and others.

In `@src/api.ts`:
- Around line 4-8: Combine the separate value and type imports into single-line
imports using inline `type` modifiers so the value and its types stay together;
e.g., import runCodemapIndex and its RunIndexOptions from
"./application/run-index" in one statement, import IndexResult as a type from
"./application/types" inline, and import loadUserConfig, resolveCodemapConfig
together with CodemapUserConfig as an inline type from "./config" to collapse
the multiple import statements into fewer lines while keeping
verbatimModuleSyntax compatibility.

In `@src/cli/cmd-context.ts`:
- Around line 91-102: The "--for" handling currently accepts an empty quoted
string because the guard only checks for undefined or tokens starting with "--";
update the condition in the parsing branch that checks the lookahead variable v
(used to set intent) to also reject an empty string (e.g., change the if that
returns the error to check v === undefined || v === "" || v.startsWith("--")),
so that intent is only assigned when v is non-empty; this keeps the behavior
consistent with the help text and prevents classifyIntent("") from receiving an
empty intent.
- Around line 248-256: The output always pretty-prints the envelope because
JSON.stringify(envelope, null, 2) is unconditional; change the console.log call
that prints envelope to respect the compact flag (opts.compact) by passing
no/zero indent when compact is true and 2-space indent otherwise (i.e., use
opts.compact to choose the indent argument for JSON.stringify on the envelope);
update the call that logs the successful envelope (symbol: envelope) to use this
conditional indent so --compact actually emits compact JSON.

In `@src/cli/cmd-index.ts`:
- Around line 36-41: Local variable named "performance" shadows the global
performance API; rename the local const to something like reportPerformance to
avoid shadowing, update the args check (const reportPerformance =
args.includes("--performance");) and pass it into runCodemapIndex as the
performance property (runCodemapIndex(db, { mode: fullRebuild ? "full" :
"incremental", performance: reportPerformance })), leaving the external API/prop
name "performance" unchanged so runCodemapIndex keeps its existing signature.

In `@src/cli/cmd-validate.test.ts`:
- Around line 19-23: Replace the hand-rolled DDL and raw INSERTs in
cmd-validate.test.ts with the production schema helper and typed insert helper:
instead of calling openDb() then running the raw "CREATE TABLE ... STRICT" DDL,
call createSchema(db) (from ../db) after openDb(), and use the project's typed
file insert helper (e.g., insertFile or similar) to populate rows so the test
uses the same column shape as production; do the same replacement for the other
occurrences around lines 30-42, and keep closeDb(db, { readonly: false }) as-is.

In `@src/db.ts`:
- Around line 250-620: The FileRow interface declares fields (size, line_count,
language, last_modified, indexed_at) as non-nullable but the underlying files
table only guarantees path and content_hash NOT NULL; to fix, either update the
SQL schema to mark those columns NOT NULL to match FileRow (modify the CREATE
TABLE for files) or relax the TypeScript model by making those properties
nullable (e.g., size: number | null, line_count: number | null, language: string
| null, last_modified: number | null, indexed_at: number | null) so reads via
query<FileRow>(...) are type-safe; locate the TypeScript interface FileRow and
the DB schema definition for files to apply the change consistently.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6d404514-84cc-4df7-8e05-71d244d0733c

📥 Commits

Reviewing files that changed from the base of the PR and between 56bb673 and efcb010.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (40)
  • .agents/lessons.md
  • .changeset/agent-friendly-cli-recipes.md
  • .oxlintrc.json
  • README.md
  • docs/research/competitive-scan-2026-04.md
  • docs/why-codemap.md
  • fixtures/golden/minimal/barrel-files.json
  • fixtures/golden/minimal/deprecated-symbols.json
  • fixtures/golden/minimal/files-hashes.json
  • fixtures/golden/minimal/index-summary.json
  • fixtures/golden/minimal/visibility-tags.json
  • fixtures/golden/scenarios.json
  • fixtures/minimal/src/utils/date.ts
  • package.json
  • scripts/benchmark-query-output.ts
  • scripts/query-golden.ts
  • src/adapters/builtin.ts
  • src/agents-init.ts
  • src/api.ts
  • src/application/index-engine.ts
  • src/application/run-index.ts
  • src/application/types.ts
  • src/benchmark.ts
  • src/cli/bootstrap.ts
  • src/cli/cmd-context.test.ts
  • src/cli/cmd-context.ts
  • src/cli/cmd-index.ts
  • src/cli/cmd-query.test.ts
  • src/cli/cmd-query.ts
  • src/cli/cmd-validate.test.ts
  • src/cli/cmd-validate.ts
  • src/cli/main.ts
  • src/cli/query-recipes.ts
  • src/config.test.ts
  • src/config.ts
  • src/db.ts
  • src/parse-worker-core.ts
  • src/parsed-types.ts
  • src/parser.ts
  • src/sqlite-db.ts

Comment thread src/cli/cmd-context.ts Outdated
Comment thread src/cli/cmd-validate.ts Outdated
…OCTOU, --compact, --for guard, README

Adopts the 7 valid items from CodeRabbit review.

A1 — `recent_markers` was alphabetical-first-20, not recency-ordered (the
markers table has no timestamp column). Rename to `sample_markers` with a
JSDoc note pointing at the proper time-ordered query (join `files.last_modified`).

A2 — `cmd-validate.ts` had a TOCTOU between existsSync and readFileSync.
Replace with a single guarded read; also drops one syscall in the common
path (open instead of stat + open).

N2 — Rename `performance` local in cmd-index.ts to `reportPerformance`
to avoid shadowing the global `performance` API.

N4 — Route the `files-hashes` golden through the bundled recipe (was
inline SQL); now exercises the recipe SQL itself and prevents drift.
Snapshot refreshed.

N5 — Add `validate` and `context` to the README "Daily commands" stripe;
they were the headline additions in this PR but weren't on the showcase.

N7 — `--for ""` was accepted as a valid intent and silently classified
as "other". Reject empty-string values with the same error as missing.

N8 — `--compact` now actually compacts: `JSON.stringify` is called
without indent in compact mode (was unconditional 2-space pretty-print).

Tests: +1 case for `--for ""` rejection. 19/19 goldens green, 24/24
cmd-context + cmd-validate tests pass.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
src/cli/cmd-context.ts (1)

122-178: Intent regexes are unanchored — --for "context" classifies as test.

Most alternatives use plain substring matching (only move\b has a word boundary), so common English words trigger spurious categories:

  • test matches "contest", "latest", "context" → --for "context" is classified as test.
  • add matches "address", "addressing".
  • spec matches "specifically", "respect".
  • fix matches "prefix", "fixture".

The classifier is documented as approximate (line 120) and agents can override, but the "context" → "test" case is jarring for the very command name and the goldens any agent will key off. Anchoring on word boundaries fixes this without changing the public contract.

♻️ Tighten alternatives with `\b`
-  if (/refactor|rename|restructur|extract|move\b/.test(t)) {
+  if (/\b(refactor|rename|restructur\w*|extract|move)\b/.test(t)) {
@@
-  if (/bug|fix|debug|error|crash|broken|regress/.test(t)) {
+  if (/\b(bug|fix|debug|error|crash|broken|regress\w*)\b/.test(t)) {
@@
-  if (/test|coverage|spec|mock/.test(t)) {
+  if (/\b(test|coverage|spec|mock)\w*\b/.test(t)) {
@@
-  if (/add|implement|create|new feature|introduce|build/.test(t)) {
+  if (/\b(add|implement|create|new feature|introduce|build)\w*\b/.test(t)) {
@@
-  if (/explore|understand|read|tour|map|overview/.test(t)) {
+  if (/\b(explore|understand|read|tour|map|overview)\w*\b/.test(t)) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/cli/cmd-context.ts` around lines 122 - 178, The regexes in classifyIntent
are unanchored and match substrings (e.g., "context" → matches "test"), so
update each pattern in classifyIntent to use word boundaries (e.g., change
/test|coverage|spec|mock/ to /\b(?:test|coverage|spec|mock)\b/) and similarly
wrap tokens in \b (and use non-capturing groups for multi-alternatives) for the
other if-conditions (refactor, bug, feature, explore, default matching) so only
whole words/phrases are matched; ensure multi-word phrases like "new feature"
are expressed as \bnew feature\b or split appropriately into anchored
alternatives.
src/cli/cmd-validate.ts (2)

99-108: Minor: when explicitPaths is non-empty, the full files table is still loaded.

For very large indexes the unconditional SELECT path, content_hash FROM files allocates an array proportional to total project size even when the caller only asked about a few paths. A targeted query (WHERE path IN (...)) would be cheaper and bound memory by request size. Not a correctness concern; flag for follow-up if scale matters.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/cli/cmd-validate.ts` around lines 99 - 108, The current logic always runs
db.query("SELECT path, content_hash FROM files") into indexed and builds
indexByPath even when explicitPaths is non-empty; change this to run a targeted
query when explicitPaths has entries (e.g. SELECT path, content_hash FROM files
WHERE path IN (...)) so only requested rows are loaded, then build indexByPath
from that result and set targets to explicitPaths; ensure the IN clause is
parameterized and consider chunking the explicitPaths if the list can be very
large to avoid SQL/parameter limits.

173-181: Asymmetric JSON envelope between success and error paths.

In --json mode the success path emits a JSON array ([...]) but the error path emits an object ({"error": "..."}). Agents must inspect the type before parsing, which is awkward. Consider emitting a consistent envelope (e.g., always {rows, error?} or wrapping the error so callers can JSON.parse and dispatch on a single shape). Defer if the agent contract is already documented elsewhere.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/cli/cmd-validate.ts` around lines 173 - 181, The error path in the catch
block returns a different JSON shape than the success path (success emits an
array, error emits {"error":...}); modify the catch to emit the same envelope as
the success path (for example JSON.stringify({ rows: [], error: msg }) when json
is true) so callers always receive a predictable object shape, keep the non-JSON
branch writing to stderr as before, and still set process.exitCode = 1; update
the branch that currently uses console.log(JSON.stringify({ error: msg })) to
use the consistent envelope instead (referencing the existing json flag and the
msg variable in the catch).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/cli/cmd-context.ts`:
- Around line 98-109: The --for argument currently accepts whitespace-only
strings because the code checks v === "" but doesn't trim; update the parsing in
the block that handles a === "--for" to trim the token (v.trim()) before
validating and assigning to intent (use the trimmed value for the
empty/startsWith checks and for setting intent) so whitespace-only inputs are
rejected the same as empty strings; reference the variables a, v, rest, intent
and the parsing block that returns the error object when the value is missing.

In `@src/cli/cmd-validate.ts`:
- Around line 142-145: The toProjectRelative function returns OS-specific
separators on Windows which breaks DB lookups; update toProjectRelative to
normalize the returned relative path to use forward slashes before it’s used
(i.e., after calling relative(projectRoot, p) replace backslashes with '/' or
use a helper that splits on path.sep and joins with '/'), and add the necessary
imports (e.g., from "node:path" like isAbsolute, relative, resolve or sep if you
use it) so indexByPath.get(rel) will match the DB’s forward-slash keys.

---

Nitpick comments:
In `@src/cli/cmd-context.ts`:
- Around line 122-178: The regexes in classifyIntent are unanchored and match
substrings (e.g., "context" → matches "test"), so update each pattern in
classifyIntent to use word boundaries (e.g., change /test|coverage|spec|mock/ to
/\b(?:test|coverage|spec|mock)\b/) and similarly wrap tokens in \b (and use
non-capturing groups for multi-alternatives) for the other if-conditions
(refactor, bug, feature, explore, default matching) so only whole words/phrases
are matched; ensure multi-word phrases like "new feature" are expressed as \bnew
feature\b or split appropriately into anchored alternatives.

In `@src/cli/cmd-validate.ts`:
- Around line 99-108: The current logic always runs db.query("SELECT path,
content_hash FROM files") into indexed and builds indexByPath even when
explicitPaths is non-empty; change this to run a targeted query when
explicitPaths has entries (e.g. SELECT path, content_hash FROM files WHERE path
IN (...)) so only requested rows are loaded, then build indexByPath from that
result and set targets to explicitPaths; ensure the IN clause is parameterized
and consider chunking the explicitPaths if the list can be very large to avoid
SQL/parameter limits.
- Around line 173-181: The error path in the catch block returns a different
JSON shape than the success path (success emits an array, error emits
{"error":...}); modify the catch to emit the same envelope as the success path
(for example JSON.stringify({ rows: [], error: msg }) when json is true) so
callers always receive a predictable object shape, keep the non-JSON branch
writing to stderr as before, and still set process.exitCode = 1; update the
branch that currently uses console.log(JSON.stringify({ error: msg })) to use
the consistent envelope instead (referencing the existing json flag and the msg
variable in the catch).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a033ea5e-a232-4d87-aed4-3e3b10e9c73d

📥 Commits

Reviewing files that changed from the base of the PR and between efcb010 and 0fafbff.

📒 Files selected for processing (7)
  • README.md
  • fixtures/golden/minimal/files-hashes.json
  • fixtures/golden/scenarios.json
  • src/cli/cmd-context.test.ts
  • src/cli/cmd-context.ts
  • src/cli/cmd-index.ts
  • src/cli/cmd-validate.ts
✅ Files skipped from review due to trivial changes (3)
  • fixtures/golden/minimal/files-hashes.json
  • src/cli/cmd-context.test.ts
  • README.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • fixtures/golden/scenarios.json
  • src/cli/cmd-index.ts

Comment thread src/cli/cmd-context.ts
Comment thread src/cli/cmd-validate.ts
…; bump SCHEMA_VERSION 2 → 3

Closes review item N1: until now FileRow declared `size`, `line_count`,
`language`, `last_modified`, `indexed_at` as non-nullable in TypeScript,
but the SQLite schema only required `path` and `content_hash` to be
NOT NULL — so a row read back via `query<FileRow>(...)` could legally
surface null for any of those columns. The same gap applied to 8 other
tables (symbols, imports, exports, components, markers, css_variables,
css_classes, css_keyframes, type_members).

This commit aligns the SQL invariants with the existing TypeScript types:
add NOT NULL to every column whose Row-interface type is non-nullable.
The DEFAULT 0 columns gain NOT NULL too so the constraint is enforced
even when the writer omits the column. `calls` and `dependencies` were
already fully constrained — no change.

`SCHEMA_VERSION` bumps 2 → 3. The existing `createSchema()` version-
mismatch detector picks up the bump on first open and triggers a full
rebuild — verified locally (meta.schema_version = "3" after one run).

Changeset bumped to minor per .agents/lessons.md (schema-breaking
changes that force a .codemap.db rebuild are minor, even pre-1.0).
Concise rewrite of the JSDocs added in the previous commits. Keeps the
non-obvious facts (FK cascade, JSON-encoded fields, recipe pointers,
related-table cross-references, total_ms vs collect_ms gotcha,
snake_case key convention on IndexTableStats) and drops the boilerplate:

- 12 row interfaces in db.ts: collapse the per-table architecture.md
  links (single source already lives in docs/architecture.md § Schema).
  Keep the high-signal hints (FK behavior on FileRow, JSDoc-tag recipes
  on SymbolRow, dependencies cross-link on ImportRow, JSON shape on
  ComponentRow.hooks_used, scope semantics on CssVariableRow,
  is_module/`.module.css` rule on CssClassRow, dedup keying on CallRow,
  null type semantics on TypeMemberRow).
- ParsedFile: drop redundant per-field one-liners that just restated
  the field name; keep error/parseError distinction, category meaning,
  CSS-only grouping, cssImportSources main-thread conversion.
- SCHEMA_VERSION: drop the v3-specific @remarks paragraph (that belongs
  in the changelog/changeset, not in code that lives forever).
- ResolvedCodemapConfig: tighten interface doc; per-field one-liners
  unchanged.
- getAdapterForExtension: collapse multi-paragraph JSDoc to one
  sentence retaining the leading-dot rule and the markers-only fallback.

application/types.ts left as-is — already balanced, and the verbose
parts there encode invariants worth keeping (snake_case keys,
total_ms != wall_time).
Two follow-ups from PR #23 review:

C1 — `cmd-context.ts:98-109` — `--for "   "` (whitespace-only) was
slipping past the `v === ""` guard added in 0fafbff and silently being
classified as "other" with `intent.input = "   "`. Reject anything that
trims to empty, and store the trimmed value so leading/trailing spaces
in quoted intents don't leak into the envelope. +2 tests
(whitespace-only rejection, trim-around-content).

C2 — `cmd-validate.ts:142-145` — Cross-platform bug. The `files.path`
column always stores POSIX paths (tinyglobby and Bun.Glob normalize on
Windows; git diff emits POSIX universally), but `path.relative()` on
Windows returns backslash-separated paths. So
`codemap validate C:\proj\src\foo.ts` would build a `src\foo.ts` lookup
key that fails to match `src/foo.ts` in the index, falsely reporting a
tracked file as `unindexed`. Mirror the same `replace(/\\/g, "/")`
normalization already in `lint-staged.config.js:12,21`. No new test —
the helper is private and the `sep === "/"` short-circuit makes it a
no-op on macOS / Linux.
…s index

Following docs/README.md conventions ("one topic per file", no flag
duplication, single-source-of-truth):

roadmap.md
- Drop `--performance` from backlog (shipped in PR #23).
- Add 4 backlog entries that the scan flagged as still open: MCP
  server, HTTP API (`codemap serve`), recipes-as-content registry +
  project-local recipes, targeted-read CLI (`codemap show <symbol>`),
  cross-agent handoff artifact (speculative).
- Expand "Non-goals (v1)" with the explicit list inherited from the
  scan's PASS table — static analysis (fallow's class), visualization
  (skyline), daemon, deep intent classification beyond `codemap context`.
  Roadmap is now the canonical home for these.

why-codemap.md
- Add "Codemap vs alternatives" comparison (Codemap / fallow /
  Aider RepoMap / LSP) — durable positioning material from the scan's
  side-by-side. Frames the four tools as solving different problems
  rather than competing for one slot.

docs/research/competitive-scan-2026-04.md
- Slim from 210 lines (full ranked adopt/watch/pass list, messaging
  lessons, next steps) to 87 lines of durable narrative: dated context,
  sources, positioning recap, raw side-by-side, "what shipped" appendix
  linking to canonical homes, "what moved to roadmap" pointer, two
  open questions still open, citations.
- Replaces sections that are now duplicates of canonical docs.

docs/README.md
- Add a `research/` row to the topic index pointing at the new folder
  convention (dated snapshot notes that link back to canonical homes).
- Add "Non-goals (v1)" row to the Single Source of Truth table —
  roadmap.md is canonical, why-codemap.md carries the consumer-facing
  framing, research/ notes link here and never re-list.
…s; add glossary, plans/ folder, and an enforcement rule

Lifts the high-signal subset of the analytics docs governance pattern:
- Rules for Agents (numbered, normative — cite by number in PR review)
- Document Lifecycle (4 doc types: Reference / Roadmap / Plan / Research)
- Existence test for whether a doc earns its place
- Top-level cap rule
- Closing rules for research notes (codifies what we did manually for
  competitive-scan-2026-04.md)

docs/README.md
- Restructure into File Ownership → Rules for Agents → Single Source of
  Truth → Document Lifecycle → Naming Conventions → Conventions.
- Move existing "Conventions" prose to the bottom as a stylistic
  addendum to the rules above.
- Add 9 numbered rules (one source of truth, ship-flow, plans, table
  freshness, relative paths, no inventory counts, no line-numbers,
  research closing, glossary updates).
- Add Document Lifecycle section with 4 doc types, the existence test,
  closing-research rules, and the top-level cap.
- Add `glossary.md`, `plans/`, `research/` rows to File Ownership.
- Add "Domain term definitions" + "Non-goals" rows to Single Source of
  Truth (canonical = glossary.md / roadmap.md, others link).

docs/glossary.md (new)
- ~70 entries covering schema/parser/recipe/agent terminology.
- Disambiguates pairs that look similar: FileRow vs `files` table, recipe
  vs query, schema vs DDL, hub vs barrel-file, fan-in vs fan-out, parser
  vs adapter, plan vs research, rule vs skill.
- Links recipe + table entries back to architecture.md schema sections
  for deep details (Rule 1 — one source of truth).

docs/plans/.gitkeep (new)
- Empty folder so the convention is in place for the first plan that
  lands. Don't add the `-plan` suffix per the naming convention.

.agents/rules/docs-governance.md + .cursor/rules/docs-governance.mdc (new)
- alwaysApply rule pointing at docs/README.md as canonical source.
- Carries the 9-rule quick checklist + the existence test + top-level
  cap so agents see them at session start without reading the full
  docs/README.md every time.
- Symlinked into .cursor/rules/ per the agents-first-convention rule.

No source code touched; 185/185 tests still pass; goldens all green.
Audited every doc against the 9 numbered rules in the new docs/README.md.
Three violations found and fixed; the rest pass.

Rule 2 — When a backlog item ships, document it in its canonical home
- architecture.md § CLI usage gains four new implementation-note paragraphs:
  * Validate wiring (cmd-validate.ts, computeValidateRows pure function,
    POSIX path normalization, exit-1 git-status semantics).
  * Context wiring (buildContextEnvelope composing existing recipes,
    classifyIntent regex routing, --compact behavior).
  * Performance wiring (RunIndexOptions.performance, parseMs on
    ParsedFile, IndexPerformanceReport assembly, total_ms gotcha).
  * Friendlier no-DB error rewriting in enrichQueryError + the new -r
    alias on --recipe (folded into existing Query wiring paragraph).

Rule 4 — Keep ownership tables current
- Key Files `cli/` row updated to mention `validate` / `context` modes
  alongside `query` / `agents init` / index modes.

Rule 6 — No inventory counts in narrative
- golden-queries.md said "15 scenarios" — now 19 after this PR's
  additions. Replaced with a qualitative descriptor + a `codemap query`
  example so the doc never goes stale on count again.

Rules 1, 3, 5, 7, 8, 9 all pass — no duplicated prose, no unintended
plans, no absolute paths to in-tree files, no line-number references
(except Rule 7's own example), competitive scan already closed, every
new term from this PR is in glossary.md.
@SutuSebastian SutuSebastian merged commit ebd4c34 into main Apr 27, 2026
9 checks passed
@SutuSebastian SutuSebastian deleted the feat/agent-friendly-cli branch April 27, 2026 12:17
@github-actions github-actions Bot mentioned this pull request Apr 27, 2026
SutuSebastian added a commit that referenced this pull request Apr 30, 2026
…ngoing tracker (#25)

## Summary

Adds durable, project-agnostic agent infrastructure to codemap's `.agents/` tree, plus an ongoing fallow capability tracker grounded in real hands-on usage data.

Three commits, reviewable independently:

1. **`docs(research): add fallow ongoing tracker`** — `docs/research/fallow.md` complementing the dated three-tool scan from PR #23. Stays in Open state per [`docs/README.md` Rule 8](https://github.com/stainless-code/codemap/blob/main/docs/README.md).
2. **`docs(agents): add docs-governance suite + agents-tier-system + comment hygiene rules`** — 3 new skills, 3 new rules, 1 modified rule, 6 new `.cursor/` symlinks.
3. **`docs(agents): add pr-comment-fact-check rule + skill`**.

No `templates/agents/` changes — these rules and skills are for codemap maintainers only, **not pushed onto npm consumers**.

## What's new

### 4 new skills (Tier 3 — discoverable, no always-on cost)

| Skill | What it does |
| ----- | ----- |
| `docs-governance` | Repo-wide docs blueprint: 5 lifecycle types, existence test, anchor-preservation discipline, surface-tier prescriptions. Codemap-active tiers: **Tier B** (`docs/`) + **Tier 0** (`.agents/`). |
| `docs-lifecycle-sweep` | The doc janitor — walks any doc surface, classifies each file Tier A/B/C with evidence, surfaces a report for user approval, executes lift / delete / slim. |
| `audit-pr-architecture` | PR-architecture audit framework: 6-step recipe (codemap reindex → derive boundary queries from `architecture.md` → `fallow audit` → cross-check STOP signals → cross-check `architecture.md` → write audit doc). STOP-signal table calibrated for codemap's `src/cli` + `src/application` + `src/adapters` + `src/db.ts` shape. |
| `pr-comment-fact-check` | Triage and fact-check PR review comments (human or bot — Bugbot, CodeRabbit, Copilot) against the actual code, project rules, and skills. Process: pull → group → fact-check → categorize → apply/reply/resolve. Hallucination patterns grounded in `docs/roadmap.md § Non-goals`. Resolve-on-merge-gate exception trimmed to a short subsection — verified live that codemap's `main` doesn't require conversation resolution (`gh api repos/stainless-code/codemap/branches/main/protection` confirms `required_conversation_resolution.enabled: false`). |

### 4 new rules

| Rule | Tier |
| ----- | ----- |
| `agents-tier-system` | **Tier 2** (auto-attached to `.agents/**` + `.cursor/**`). Carries the durability sub-rules: no specific filenames / hashes / line numbers as canonical examples — they rot. |
| `concise-comments` | **Tier 1** (always-on, globbed to `ts/tsx/css/html/md`). Examples in "Keep" are codemap-shape (SQLite quirks, parser idiosyncrasies, oxc-resolver returning null). |
| `preserve-comments` | **Tier 1** (always-on, globbed to `ts/tsx/css/html`). Pairs with `concise-comments`. |
| `pr-comment-fact-check` | **Tier 1** (always-on, intent-triggered priming). Cross-links `docs-governance` since fact-checking comments about docs uses the same anchor-preservation discipline. |

### 1 modified rule

- `docs-governance.md` — slimmed from `alwaysApply: true` to **Tier 2** (`globs: "docs/**, .agents/**", alwaysApply: false`). Now explicitly the priming layer pointing at the new skill. Cited Rule numbers (1–9) in `docs/README.md` left untouched per the anchor-preservation discipline.

### 8 new `.cursor/` symlinks

Per [`agents-first-convention`](https://github.com/stainless-code/codemap/blob/main/.agents/rules/agents-first-convention.md): `.agents/` is source of truth, `.cursor/` is symlinks. (4 rules + 4 skills.)

## How the new pieces fit together

```text
docs/README.md                                  ← Rules 1–9 cited from across docs/ + .agents/
  │
  ├── doc-touching edit primes →
  │     .agents/rules/docs-governance.md        ← Tier 2 (auto-attached to docs/**, .agents/**)
  │       │
  │       └── deep reference →
  │             .agents/skills/docs-governance/SKILL.md
  │                ├── operationalised by →
  │                │     .agents/skills/docs-lifecycle-sweep/SKILL.md
  │                └── audit substrate prescriptions used by →
  │                      .agents/skills/audit-pr-architecture/SKILL.md
  │
  ├── any rule/skill edit primes →
  │     .agents/rules/agents-tier-system.md     ← Tier 2 (auto-attached to .agents/**, .cursor/**)
  │
  ├── any code edit primes →
  │     .agents/rules/concise-comments.md       ← Tier 1 (always-on, scoped via globs)
  │     .agents/rules/preserve-comments.md      ← Tier 1 (always-on, scoped via globs)
  │
  └── PR-comment intent primes →
        .agents/rules/pr-comment-fact-check.md  ← Tier 1 (always-on, intent-triggered)
          │
          └── deep reference →
                .agents/skills/pr-comment-fact-check/SKILL.md
```

Plus the `docs/research/fallow.md` ongoing tracker, complementing PR #23's dated competitive scan.

## Test plan

- [x] `bun run check` passes locally (build, format:check, lint:ci, test, typecheck, test:golden — 185 tests across 18 files, 19 golden scenarios). Re-run after the third commit; still green.
- [x] All `.cursor/` symlinks resolve (`ls -la .cursor/rules/ .cursor/skills/`).
- [x] Cited Rule numbers in `docs/README.md` unchanged (`rg "Rule [0-9]+" docs/ .agents/` shows the same anchors as before).
- [x] Branch protection check verified live for `pr-comment-fact-check` skill's "merge-gate exception" subsection (codemap's `main` has `required_conversation_resolution.enabled: false`, so the default flow applies).
- [ ] Reviewer spot-checks `audit-pr-architecture` STOP-signal table (§ 4) and `pr-comment-fact-check` hallucination patterns (1–4 are codemap-thesis-shaped) since those are the most opinionated sections.
- [ ] CI green.

## No changeset

Only `.agents/`, `.cursor/`, and `docs/` touched. None of those ship to npm consumers (`package.json` `files`: `CHANGELOG.md`, `dist`, `templates`). Prior pure-docs / pure-agents commits in this repo (e.g. `f9726a9`, `8a8a791`) shipped without changesets — same precedent here.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant