Skip to content

HITMANdark07/neatcodeai

Repository files navigation

                          _                     _
   _ __    ___    __ _   | |_    ___   ___   __| |   ___
  | '_ \  / _ \  / _` |  | __|  / __| / _ \ / _` |  / _ \
  | | | ||  __/ | (_| |  | |_  | (__ | (_) | (_| | |  __/
  |_| |_| \___|  \__,_|   \__|  \___| \___/ \__,_|  \___|

🧠 neatcode

Local-first repo intelligence for AI coding agents. The graph your agent wishes it had.

npm version npm downloads license node types mcp


Stop letting your agent re-grep your repo on every turn. neatcode indexes your TypeScript codebase into a real AST graph, learns the conventions your code already follows, and answers your agent's structural questions over MCP — deterministic, no LLM in the hot path.

   ┌──────────────────┐        MCP         ┌─────────────────────────────────┐
   │  💻 your editor  │  ◀────stdio─────▶  │  ⚙️  neatcode-mcp  (11 tools)    │
   │                  │                    │                                 |
   │  Claude Code     │                    │  🔍 query_graph     📍 find_node │
   │  Cursor          │                    │  🛤️  trace_flow      ✅ validate │
   │  Codex           │                    │  💡 propose_rule    📚 get_rules │
   └──────────────────┘                    │  📝 add_note    📋 repo_overview │
                                           │  ⮕ accept_proposed_rule         │
                                           │  ⮕ derive_candidates            │
                                           │  ⮕ accept_derived_candidates    │
                                           └────────────────┬────────────────┘
                                                            │
                                                ┌───────────▼───────────┐
                                                │   📂 .neatcode/       │
                                                │    ├── graph.db       │
                                                │    ├── skills.yaml    │
                                                │    ├── decisions.yaml │
                                                │    └── REPO_OVERVIEW  │
                                                └───────────────────────┘

💡 Why

Without neatcode With neatcode
Agent re-greps the repo every turn Agent calls query_graph against an indexed AST
"What conventions does this repo follow?" → vibes Heuristic miner derives conventions from real code
Agent writes BookingHandler despite a Controller convention validate_diff flags it before the file is written
Rules live in tribal memory or stale CONTRIBUTING.md Rules live in .neatcode/skills.yaml, validated bidirectionally
Each chat starts cold get_repo_overview ships the one-page brief at session start

🚀 Quickstart — 3 commands

# 1. Install (one tarball, both binaries)
npm i -g @neatcodeai/cli

# 2. Index your repo
cd ~/your/typescript/repo
neatcode init

# 3. Wire it into Claude Code
neatcode claude install

Restart Claude Code. Your agent now has 11 structural tools — and a fresh .neatcode/REPO_OVERVIEW.md for instant context.

🎯 Founder's target: installed in 10 minutes, useful in 1 hour.

🎬 What it looks like in practice

👤 You: "Where do we handle booking cancellation?"

🤖 Agent: [calls query_graph with "booking cancellation"]
       ↓
       📍 BookingsController.cancel       (apps/api/src/bookings/…)
       📍 BookingsService.cancel          (called by Controller)
       📍 RefundService.issueRefund       (called by Service)
       📍 BookingCancelledEvent           (emitted at end)

       Here's the flow: Controller → Service → RefundService,
       with a domain event published on completion.

vs. without neatcode: agent runs 4 grep calls, reads 18 files, and still misses the event publisher.


🔷 TypeScript compatibility

neatcode ships TypeScript types and is built around ts-morph. It indexes any TypeScript codebase that compiles.

What Compatibility
TypeScript versions 5.05.7+ (uses ts-morph 24.x; tracks the bundled compiler)
File extensions .ts, .tsx (skips .d.ts and .generated.ts(x)); .js / .cjs not yet indexed
Module systems ESM, CommonJS, mixed — output target doesn't matter
tsconfig.json Auto-detected at repo root; respects paths, baseUrl, composite
JSX / TSX Yes — .tsx parsed, JSX edges emitted
Decorators Stage-3 standard + experimental (NestJS, TypeORM, class-validator)
Type-aware queries Uses TS TypeChecker for cross-file call-graph resolution
Strict mode Recommended but not required
Monorepos pnpm / yarn / npm workspaces — each package gets its own qualified_name namespace
Frameworks NestJS, React, Next.js, Express, Fastify (auto-detected; no rule packs)

Not on TypeScript? neatcode v0.1 is TS-only by design — Python, Go, and JS support are roadmapped (see Roadmap).


⚡ CLI reference

neatcode <command> [options]

📥 Indexing

Command What it does
neatcode init First-time setup. Creates .neatcode/, indexes every .ts/.tsx file, runs the heuristic miner, drops REPO_OVERVIEW.md.
neatcode sync [--force] Re-index changed files. Content-hash cached — editing 3 files re-parses 3 files.
neatcode ask "<question>" Ad-hoc graph query from the terminal. Same engine as query_graph over MCP.

🎓 Skills (conventions)

Command What it does
neatcode skills derive [--threshold 0.85] [--min-population 3] Mine the graph for high-coverage patterns. Writes skills.candidates.yaml.
neatcode skills accept <id> [--all] [--confidence high|medium] [--local] Promote candidates into skills.yaml (committed) or skills.local.yaml (gitignored).
neatcode skills reject <id> [--reason "…"] Mark a candidate as rejected so the next derive skips it.

✅ Validation

Command What it does
neatcode validate [<files…>] [--json] No args → check whole graph. With files → treat as planned diff. Pre-existing offenders are grandfathered under scope: "new".
neatcode exception add <rule_id> <location> [--days N] [--reason "…"] Silence a specific violation. Auto-expires with --days.
neatcode exception list Show active exceptions.
neatcode exception revoke <rule_id> <location> Append-only revoke (original entry preserved).

🔌 Editor integration

Command What it does
neatcode claude install Merges .mcp.json, appends MCP guidance to CLAUDE.md. Idempotent.
neatcode claude uninstall Reverses both. Pre-existing CLAUDE.md content is preserved.
neatcode cursor install (coming v0.2) Wires neatcode-mcp into Cursor's MCP config.
neatcode codex install (coming v0.2) Wires neatcode-mcp into Codex.

🔗 MCP integration

The agent gets 11 tools the moment Claude Code restarts after neatcode claude install:

Discovery + queries

Tool When the agent calls it
get_repo_overview Once per session. Returns frameworks, top symbols, layout, active rules, dirty-file status.
query_graph "What handles X?", "what calls Y?" — keyword-scored search with optional 1-hop expansion.
find_node Exact lookup by name or qualified_name. Returns merged class+method decorators.
trace_flow Multi-hop path traversal. "From BookingsController.create to the DB" returns the call chain.

Rules + validation

Tool When the agent calls it
get_rules Returns active rules, candidates, rejected list, and repo context for curation flows.
validate_diff Pre-flight on a planned change. Returns violations + four-option suggestions block.
propose_rule_from_prompt Inspects a user utterance for rule-language ("never", "must", "always"). Surfaces a structured proposal.
accept_proposed_rule Promote a single proposed rule into skills.yaml.
derive_candidates Run the heuristic miner on demand and return candidate rules.
accept_derived_candidates Bulk-accept miner candidates by id, confidence, or --all.

Memory

Tool When the agent calls it
add_note Persist a fact the user shared. Appends to .neatcode/memory/notes-YYYY-MM-DD.md.

All deterministic. No LLM call inside the server. The agent is the brain; neatcode is the spine.


📂 What lives in .neatcode/

neatcode init creates the directory and seeds it with the indexer output and miner proposals. The remaining files appear on demand as you accept rules, record exceptions, and let the agent take notes.

Created by neatcode init:

<repo-root>/
├── .neatcodeignore                team-shared excludes (commit it)
└── .neatcode/
    ├── graph.db                   SQLite graph         (regenerate; should gitignore)
    ├── skills.candidates.yaml     miner proposals      (regenerated each sync)
    ├── REPO_OVERVIEW.md           session-start brief  (commit it)
    ├── plans/                     /writing-plans skill scaffold (commit it)
    └── specs/                     /brainstorming skill scaffold (commit it)

Appears on demand:

.neatcode/
├── skills.yaml                   on first `skills accept`              (commit it)
├── skills.local.yaml             on `skills accept --local`            (should gitignore)
├── skills.rejected.yaml          on first `skills reject`              (commit it)
├── decisions.yaml                on first exception/supersede          (commit it)
├── memory/                       on first `add_note` MCP call          (commit it)
└── mcp.log                       on first MCP server start             (should gitignore)

ℹ️ neatcode init doesn't touch your .gitignore. Add the regeneratable bits yourself:

.neatcode/graph.db*
.neatcode/skills.candidates.yaml
.neatcode/skills.local.yaml
.neatcode/mcp.log

graph.db is regeneratable from a single neatcode sync. The committed files above form the team-shared memory of the repo — that's the part you code-review.


📐 How rules emerge

Three sources, one lifecycle:

  1. Heuristic miningneatcode skills derive proposes candidates above the coverage threshold. Four primitives mined today: decorator-required, annotation-forbidden, naming-pattern, folder-naming-convention.
  2. Prompts — when the user says "all classes with @Controller must use @UseGuards", the agent calls propose_rule_from_prompt. A local keyword classifier — no LLM in the loop — extracts a structured candidate. User confirms, agent runs skills accept.
  3. Manual — hand-edit .neatcode/skills.yaml (create it on first rule). The schema is documented and stable.

Rules are validated bidirectionally:

  • A diff that violates a rule → four-option UX (record exception · time-bounded · supersede the rule · abort).
  • A rule that no longer matches the codebase → can be superseded with an entry in decisions.yaml.

🧩 The six primitives

Primitive Mined? Example
decorator-required yes classes with @ApiTags must also have @Controller
annotation-forbidden yes classes with @Controller must not carry @Deprecated
naming-pattern yes classes with @Module end with "Module"
folder-naming-convention yes files in apps/api/services/ end with .service.ts
import-forbidden via prompt never import from packages/internal/
edge-forbidden via prompt controllers must not call repositories directly

Layer constraints ("controllers can't reach repositories") are expressed via edge-forbidden — no special "layer" type.

🌱 Default rule scope: new

Rules default to scope: "new" — pre-existing violations are grandfathered. Only code introduced after the rule was promoted gets checked. Set scope: "all" in YAML to enforce against existing code.

This avoids the classic "we accepted 30 conventions and now CI is on fire" problem.


🏗️ Architecture

       ┌──────────────────────────────────────────────────┐
       │  📜 ts-morph parser  ──▶  🗂️  polymorphic graph  │
       │                              (SQLite)            │
       └─────────────────────┬────────────────────────────┘
                             │
       ┌─────────────────────┼─────────────────────┐
       ▼                     ▼                     ▼
  🔍 query_graph        🎓 skills derive      ✅ validate_diff
  📍 find_node          (heuristic miner)        (engine.ts)
  🛤️ trace_flow                │                       │
       │                       ▼                       ▼
       │                skills.candidates      active rules ∩
       │                    → accept           decisions.yaml
       ▼                                              │
  🤖 agent answers ◀─────────────────────────  ⚠️ violations
                                              + 4-option UX

Every relationship gets a confidence label (EXTRACTED | INFERRED | AMBIGUOUS); the validator never fires on rules built solely from AMBIGUOUS edges. The repo-root-relative qualified_name is the FK that ties nodes, edges, rules, and decisions together. There's no LLM in the hot path of any MCP tool — the LLM lives in the agent harness (Claude Code, Cursor, Codex), and neatcode is the spine.


📦 Packages

The CLI bundles everything you need; the others are split for advanced use.

Package Install for What it gives you
@neatcodeai/cli Most users neatcode + neatcode-mcp binaries (depends on the others).
@neatcodeai/mcp Bare MCP server The stdio MCP binary alone.
@neatcodeai/core Library users parseFile, Database, ask, miner — all typed.

Single install gets you everything:

npm i -g @neatcodeai/cli
which neatcode neatcode-mcp

🛠️ Develop

pnpm install           # builds better-sqlite3 native module
pnpm build             # builds all three packages
pnpm typecheck         # tsc --noEmit across packages
pnpm test              # vitest run
pnpm test:watch
pnpm clean

# Smoke-test
node packages/cli/dist/index.js --help

Node 20+, TypeScript strict + verbatimModuleSyntax, ESM only.


🗺️ Roadmap

  • v0.1 (shipped) — TypeScript-only, 11 MCP tools, validation engine, four-option UX, heuristic miner with four primitives, Claude Code installer.
  • v0.2 — Cursor + Codex installers, import-forbidden / edge-forbidden mining, agent-proposed rules (skills derive --with-agent).
  • v0.3 — Watcher mode (neatcode dev), JavaScript / .js / .cjs indexing, TypeScript LSP integration.
  • Later — Python via tree-sitter, Go via go/parser, multi-language graphs joined by import-edge inference.

Issues, feature requests, and convention horror stories: github.com/HitmanDark07/neatcodeai/issues.


🛡️ Hard rules (project guarantees)

  • No framework rule packs — conventions emerge per-repo.
  • Decorators / generics / JSX live in extra JSON, not schema columns.
  • qualified_name is always repo-root-relative.
  • Rules built solely on AMBIGUOUS edges never enforce.
  • v0.1 doesn't solve general NestJS DI — @Module({ providers, controllers, imports }) arrays become direct edges and we stop there.

📄 License

MIT · built with ❤️ by @HitmanDark07

If neatcode helps your agent stop guessing, star the repo.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors