domimap
by SunArthurX
README.md
# domimap — Local-first Knowledge Retrieval Engine
**Domain + Map**: turn multiple Java repositories, project docs, and human knowledge into one queryable, evidence-cited domain map.
**English** | [简体中文](README.zh-CN.md)
[](https://github.com/SunArthurX/domimap/actions/workflows/ci.yml) [](https://github.com/SunArthurX/domimap/blob/main/pyproject.toml) [](https://github.com/SunArthurX/domimap/blob/main/pyproject.toml) [](https://github.com/SunArthurX/domimap/blob/main/LICENSE)
## What is domimap?
domimap is a local-first knowledge retrieval engine that builds a queryable domain map from multiple Java repositories, project documentation, and human-curated knowledge. It offers CLI, MCP (Model Context Protocol) server, and Web UI interfaces — so both humans and AI agents can search, trace, and **cite evidence** across an entire codebase. Building the graph is deterministic and **LLM-free**; language models only ever appear as optional, clearly-labelled enhancement layers.
## Key Features
| Feature | Description |
|---|---|
| **Multi-repo aggregation** | Index many repos into one unified graph |
| **Hybrid retrieval** | BM25 lexical + graph expansion + domain seeds (+ optional local embeddings) |
| **Evidence citation** | Every result carries a file path + immutable evidence ID |
| **Immutable evidence** | Source edits/deletions never break old citations |
| **Knowledge timeline** | Content-era extraction (explicit dates/versions, not file mtime); expired/superseded docs are ineligible by default, `--as-of` for historical ranges |
| **Honest refusal** | Four refusal gates — no near-name guessing, no hallucinated hits |
| **Knowledge loop** | Save notes with typed claims → build detects changed support → review queue (`recheck`) → confirmed citations; stale claims are flagged in search |
| **Trusted context** | AGENTS.md/SOUL.md load only from explicitly registered roots (`trust add`), with nested-scope resolution and change detection |
| **Workspace lifecycle** | Source identity survives moves (`rebind`); whole-workspace export/restore with per-file checksums |
| **Client connect** | One-command native setup for Claude Code / Codex / ZCode / DSH (`domimap connect`), idempotent with backups |
| **MCP integration** | Native MCP stdio server (7 read-only `kg_*` tools; 2 write tools behind `--enable-write`) |
| **Service navigation** | `map` (RPC, Maven modules, topics), `card` (routes, tables, jobs, docs), `trace` along causal edges |
| **Graph indexes** | `graph.json` hardlinked to the immutable generation; `graph.db` neighbors; `graph.json.idx.db` postings read on demand |
| **Zero core dependencies** | Pure Python stdlib; optional deps only enhance |
## Quick Start
```bash
git clone https://github.com/SunArthurX/domimap.git && cd domimap
# No install needed — pure stdlib
# Single repo: --merge puts the graph directly in out/idx
python3 -m domimap build ~/my-java-projects -o out/idx --merge
# Multi-repo workspace (recommended): auto-discover sub-repos → merged graph
# + evidence store + incremental manifest
python3 -m domimap build ~/work/my-workspace --discover -o out/idx
python3 -m domimap update -o out/idx # incremental; ms-level no-op if unchanged
# Or install as a CLI
pip install . # provides the `domimap` command
# Optional PDF/DOCX ingestion
pip install pypdf python-docx
```
### CLI
```bash
# Build & update
python3 -m domimap build ~/work/my-workspace --discover -o out/idx # merged graph + evidence store
python3 -m domimap build ~/repo-a -o out/idx --merge # single repo
python3 -m domimap update -o out/idx # incremental
python3 -m domimap gc -o out/idx --keep-gens 2 # drop old generations and unreferenced blobs
# Search (Chinese & English)
python3 -m domimap query "订单改价 changePrice" -g out/idx/graph.json
python3 -m domimap query "ai_resource 表 定义 写入" -g out/idx/graph.json
python3 -m domimap doc "灰度发布 规范" -g out/idx/graph.json # doc lane (same params as MCP)
python3 -m domimap query "灰度发布" --as-of 2026-01-01 -g out/idx/graph.json # historical range
# Domain map / impact / scenario cards
python3 -m domimap domain -g out/idx/graph.json
python3 -m domimap impact "OrderService" -g out/idx/graph.json # causal edges only, partial-flagged, --max-nodes
python3 -m domimap scenario req "订单改价 需要防并发" -g out/idx/graph.json
python3 -m domimap map -g out/idx/graph.json # services, Maven deps, topics
python3 -m domimap card order-service -g out/idx/graph.json # routes, tables, jobs, RPC, docs
python3 -m domimap trace OrderService -g out/idx/graph.json # forward causal trace
# Read evidence by ID (immutable — survives source changes)
python3 -m domimap read <evidence_id> --store out/idx/store.db
# Machine-readable graph schema (feed it to your AI client)
python3 -m domimap schema
# Web UI (loopback only)
python3 -m domimap ui -g out/idx/graph.json --port 8080
```
### Knowledge & workspace lifecycle
```bash
# Notes with typed claims; amend needs --expected-revision (optimistic concurrency)
python3 -m domimap note submit --body "改价必须带版本号" --claims '[{"type":"decision","statement":"...","evidence":[]}]' -g out/idx/graph.json
python3 -m domimap note amend <note_id> --body "..." --expected-revision 1 -g out/idx/graph.json
python3 -m domimap recheck list -g out/idx/graph.json # claims whose support changed after a rebuild
python3 -m domimap recheck confirm <note_id> 0 -g out/idx/graph.json
# Markdown interop with conflict preview, and knowledge backup/restore
python3 -m domimap kb export out/notes-md -g out/idx/graph.json
python3 -m domimap kb import out/notes-md/<note>.md --preview -g out/idx/graph.json
python3 -m domimap kb backup out/kb-snapshot -g out/idx/graph.json
# Trusted AGENTS.md/SOUL.md roots (never auto-trusted from scanned sources)
python3 -m domimap trust add myrules ~/my-rules -g out/idx/graph.json
python3 -m domimap context -g out/idx/graph.json
# Whole workspace (evidence store + graph + source registry + knowledge) as a checksummed bundle
python3 -m domimap export-workspace out/idx out/backup-dir
python3 -m domimap restore-workspace out/backup-dir out/restored
# Source root moved? Logical identity (sids, node IDs) stays stable
python3 -m domimap rebind <label> /new/path -o out/idx
# Native client setup (idempotent, backed up, managed remove)
python3 -m domimap connect claude -g out/idx/graph.json # also: codex | zcode | dsh
python3 -m domimap clients # per-client diagnostics
```
### Optional LLM enrichment (post-build, off by default)
One command sends Doc materials to a **configurable** LLM (Anthropic-compatible API, default GLM-5.3) and files the results as **inference drafts — never facts**:
```bash
python3 -m domimap enrich -g out/idx/graph.json --limit 5 # docs (default, incremental)
python3 -m domimap enrich -g out/idx/graph.json --targets domain # per-domain materials
python3 -m domimap enrich -g out/idx/graph.json --dry-run # preview, no network
python3 -m domimap enrich -g out/idx/graph.json --json --budget-tokens 200000
```
- **Config** (flag > env > default): `DOMIMAP_LLM_ENDPOINT`, `DOMIMAP_LLM_MODEL` (glm-5.3), `DOMIMAP_LLM_MAX_TOKENS` (1024), `DOMIMAP_LLM_TIMEOUT` (120s); key from `GLM_API_KEY` / `ANTHROPIC_API_KEY` / `DOMIMAP_LLM_KEY_HELPER` (missing key or busy lock → exit code 6, never a silent downgrade).
- **Discipline**: drafts go into `knowledge.db` beside the graph with `conf=LLM, prov=knowledge:llm` and claims `inference/proposed`; only human `accept` makes them confirmed knowledge. `evidence_paths` are server-side whitelist-validated (fabricated paths dropped + audited). Idempotent re-runs (zero calls, zero new notes on unchanged graph); superseded docs auto-withdraw old LLM notes; every call is journaled to `enrichment.jsonl` (crash-safe, no double billing).
- **Hardening**: 4xx fails that item without retry; 429/5xx honor `Retry-After` with jittered backoff; `--budget-tokens` stops cleanly; per-directory mutex (`.enrich.lock`); materials wrapped in delimiters and declared "data, not instructions" (prompt-injection mitigation); `--json` prints per-item detail and cost estimate.
- **Threat model**: the key lives only in process memory; endpoint is yours to choose — data will be sent there; human review is the final gate against adversarial content.
### Optional query-time layers (all off by default; offline core semantics unchanged)
- **Semantic bridge** (`DOMIMAP_SEMANTIC_BRIDGE=1` or `query --semantic`): when raw coverage < 60% and the query contains Chinese, the same configurable LLM generates English keywords, which are grounded against the index vocabulary before merging into the candidate union; any failure skips cleanly and refusal semantics stay byte-identical.
- **LLM rerank** (`DOMIMAP_LLM_RERANK=1` or `query --rerank`): re-orders the top-N fused candidates via the LLM (opaque ids only — zero injection surface). Measured zero effect on our corpora; kept as an isolated, contract-tested option.
- **Embedding fusion** (`domimap embed` to build the index, then `--embed`/`DOMIMAP_EMBED=1`): local **bge-small-zh-v1.5** via `pip install fastembed` (offline, free; or `DOMIMAP_EMBED_BACKEND=api` for bigmodel embedding-3), fused with the lexical order via RRF (K=60). A **fusion eligibility gate** keeps lexical authority for definition-identifier / code-location queries. Real A/B on both corpora: pub 23/97→36/97, dev 19/36→26/36, zero regressions, negatives unchanged.
## MCP Server
```bash
python3 -m domimap serve -g out/idx/graph.json
```
Connect **Claude Code / ZCode / Codex / DSH** (per-client setup in [docs/clients.md](docs/clients.md)):
```json
{
"mcpServers": {
"domimap": {
"command": "python3",
"args": ["-m", "domimap", "serve", "-g", "/path/to/out/idx/graph.json"]
}
}
}
```
| Tool | Description |
|---|---|
| `kg_explore` | Main search: lexical seeds + graph expansion, returns services/classes/methods/routes/tables/docs with confidence and provenance |
| `kg_read` | Read evidence by ID (immutable — survives source changes) |
| `kg_domain_map` | Domain map: domain → services/tables/topics/docs |
| `kg_impact` | Impact analysis: reverse dependencies of a symbol |
| `kg_doc_search` | Full-text document search |
| `kg_troubleshoot` | Symptom → graph+docs dual recall → ranked suspects |
| `kg_context` | Trusted AGENTS.md/SOUL.md context (only from roots registered via `trust add`) |
Write tools — **only with `serve --enable-write`**: `kg_feedback` (record query feedback; relayed verdicts are stored as non-authoritative `agent_relay`) and `kg_note` (submit/amend/withdraw/accept notes; claims stay `proposed`).
**Recommended agent loop**: `kg_domain_map` for the big picture → `kg_explore` to search → `kg_read(ev_id)` for the immutable source → cite **path + ev_id**; on `refused=true`, say so instead of guessing.
### Web UI
```bash
python3 -m domimap ui -g out/idx/graph.json --port 8080 # loopback only, zero deps
```

### Machine-readable schema
`domimap schema` outputs the full node/edge taxonomy, confidence & provenance semantics, tool list and refusal gates as JSON. A contract test keeps it in sync with the implementation (zero drift). Human reference: [docs/knowledge-graph.md](docs/knowledge-graph.md).
## Architecture
```mermaid
flowchart TB
subgraph SRC["Workspace: code & docs"]
REPOS["Java repos · MyBatis XML · SQL DDL"]
DOCS["Markdown · HTML · PDF* · DOCX* · TS/JS/Vue"]
end
subgraph BUILD["Build — deterministic, no LLM"]
SCAN["Scanners (lite_scan)<br/>GBK/GB18030 auto-detect"]
CHUNK["Doc chunking<br/>long docs → overlapping segments"]
GRAPH["Knowledge Graph<br/>14 node kinds · 15 edge kinds<br/>graph.json hardlink · graph.db neighbors"]
STORE["Evidence Store (SQLite)<br/>ev_id · content-addressed<br/>immutable generations"]
SCAN --> CHUNK --> GRAPH
SCAN --> STORE
end
subgraph ENGINE["Search Engine (search.py)"]
BM25["BM25 k=1.2 b=0.75<br/>identifier ×3 · DDL semantic ×2"]
EMB["Semantic lane (optional)<br/>local embeddings · RRF fusion<br/>+ eligibility gate"]
EXPAND["Graph expansion<br/>CALLS · READS/WRITES · MQ edges"]
LANE["Doc lane merge<br/>+ content-era time notes"]
GUARD["4 honest-refusal gates"]
end
KBX["Knowledge Base (SQLite)<br/>human notes · claims · review workflow"]
ENR["`domimap enrich` (optional post-build)<br/>LLM draft notes · conf=LLM<br/>human review before facts"]
CLI["CLI"]
MCP["MCP stdio server<br/>9 kg_* tools"]
UI["Web UI (loopback)"]
REPOS --> SCAN
DOCS --> SCAN
GRAPH --> BM25
GRAPH -.optional.-> EMB
STORE --> LANE
KBX -.attach.-> BM25
ENR -.drafts.-> KBX
BM25 --> EXPAND --> LANE --> GUARD
EMB --> LANE
GUARD --> CLI
GUARD --> MCP
GUARD --> UI
```
\* = optional dependency required (`pip install pypdf python-docx`)
### Query data flow
```mermaid
flowchart LR
Q["query text"] --> TOK["Tokenize: CJK 2-gram + Latin identifiers<br/>EN bridge only as query-time fallback"]
TOK --> G1{"Generic words only?"}
G1 -->|yes| R1["Refuse: no substantive concept"]
G1 -->|no| G2{"All Latin identifiers absent?"}
G2 -->|yes| R2["Refuse: no near-name guessing"]
G2 -->|no| SCORE["BM25 scoring<br/>+ exact-name ×3 + DDL semantic ×2"]
SCORE --> G3{"Coverage ≥ 30%?"}
G3 -->|no| R3["Refuse: coverage too low<br/>+ keyword suggestions"]
G3 -->|yes| OUT["Seeds + 1-hop graph expansion + doc-lane merge<br/>→ path + ev_id + conf/prov + time_note"]
```
Evolution & maturity plan: [docs/evolution.md](docs/evolution.md) · Full schema reference: [docs/knowledge-graph.md](docs/knowledge-graph.md)
## Benchmark Results
Five systems — domimap and four open-source competitors ([Codebase-Memory-MCP](https://github.com/DeusData/codebase-memory-mcp), [claude-obsidian](https://github.com/AgriciDaniel/claude-obsidian), [Graphify](https://github.com/Graphify-Labs/graphify), [CodeGraph](https://github.com/colbymchenry/codegraph)) — were driven by the **same host model (GLM-5.3), the same system prompt, the same turn/tool budget, and a per-system copy of the same workspace**. Scoring is mechanical answer-layer citation matching (bidirectional path match). All numbers are **same-session developer evaluations, not the frozen independent confirmation run** required by [specs/benchmark.md](specs/benchmark.md); the release gate (`make release-check`) therefore stays closed.
### Dev set — enterprise Java corpus (33 questions)
27 scored positives (code 8 · cross-repo 8 · doc 5 · fresh 6) + 4 negatives + 2 locator-diagnostic.
| System | code | cross-repo | doc | fresh | **Positives** | Negatives (abstain) | Locator |
|---|---|---|---|---|---|---|---|
| **domimap** | **8/8** | **8/8** | **4/5** | **4/6** | **24/27 (89%)** | 4/4 | 2/2 |
| Codebase-Memory-MCP | 0/8 | 8/8 | 0/5 | 1/6 | 9/27 (33%) | 4/4 | 0/2 |
| CodeGraph | 3/8 | 0/8 | 0/5 | 0/6 | 3/27 (11%) | 4/4 | 0/2 |
| Graphify | 2/8 | 0/8 | 0/5 | 0/6 | 2/27 (7%) | 4/4 | 1/2 |
| claude-obsidian | 0/8 | 0/8 | 0/5 | 1/6 | 1/27 (4%) | 4/4 | 1/2 |
### Public corpus — 27 unseen open-source families (40 questions)
32 scored positives (8 per category) + 4 negatives + 4 locator-diagnostic.
| System | code | cross-repo | doc | fresh | **Positives** | Negatives (abstain) | Locator |
|---|---|---|---|---|---|---|---|
| **domimap** | **6/8** | **8/8** | 4/8 | **4/8** | **22/32 (69%)** | 4/4 | 1/4 |
| Codebase-Memory-MCP | 5/8 | 8/8 | 3/8 | 1/8 | 17/32 (53%) | 4/4 | 2/4 |
| claude-obsidian | 5/8 | 3/8 | 4/8 | 1/8 | 13/32 (41%) | 4/4 | 3/4 |
| Graphify | 3/8 | 0/8 | **5/8** | 3/8 | 11/32 (34%) | 4/4 | 3/4 |
| CodeGraph | 2/8 | 3/8 | 0/8 | 0/8 | 5/32 (16%) | 4/4 | 0/4 |
Paired differences on the public corpus (n = 36 = 32 positives + 4 negatives):
| Comparison | domimap | Competitor | Difference |
|---|---|---|---|
| vs Codebase-Memory-MCP | 26/36 | 21/36 | +13.9 pp |
| vs claude-obsidian | 26/36 | 17/36 | +25.0 pp |
| vs Graphify | 26/36 | 15/36 | +30.6 pp |
| vs CodeGraph | 26/36 | 9/36 | +47.2 pp |
All four paired differences are positive on both corpora, but the gaps narrow sharply on the English-heavy public corpus: Graphify leads on document reasoning there, and three competitors beat domimap on the locator-diagnostic subset. These results are scoped to these two corpora and this host and are not a claim of general superiority. Raw artifacts, runners and the frozen protocol live under [`benchmarks/`](benchmarks/README.md).
### Performance
| Metric | Value |
|---|---|
| Index build (9 repos, 37K files) | 14 minutes |
| Query latency (single query) | < 1 second |
| Full 33-question evaluation | 1.2 seconds (diagnostic track) |
| Memory (peak RSS, 9-repo index) | ~4.3 GB |
## Supported Formats
| Format | Status | Notes |
|---|---|---|
| Java (.java) | ✅ Full | GBK/UTF-8 auto-detect, comments indexed |
| MyBatis XML (.xml) | ✅ Full | Mapper namespace, SQL statements, table extraction |
| SQL DDL (.sql) | ✅ Full | CREATE TABLE parsing, DDL semantic boost |
| Markdown (.md) | ✅ Full | Front-matter (valid_until/superseded_by) |
| HTML (.html) | ✅ Full | Tag stripping, entity decoding |
| Plain text (.txt) | ✅ Full | GBK fallback |
| PDF (.pdf) | ⚠️ Optional | Requires `pypdf` |
| DOCX (.docx) | ⚠️ Optional | Requires `python-docx` |
| TypeScript/JavaScript | ✅ Basic | Frontend framework detection |
| Vue (.vue) | ✅ Basic | Component scanning |
## Development
```bash
make ci # what CI runs: structural spec check + full test suite
make verify # local gate: additionally verifies evidence fingerprints in out/verification
make release-check # release gate — fails by design until the frozen confirmation run exists
make mini # build a mini test graph and try a query
```
Optional parsers for the PDF/DOCX ingestion contracts: `pip install pypdf python-docx` (those tests skip when absent).
### Project Structure
```
domimap/
├── domimap/ # Core Python package (zero deps)
│ ├── lite_scan.py # Multi-format scanner (Java/MyBatis/DDL/MQ/docs)
│ ├── chunking.py # Long-doc segmentation (BM25 + embedding dual-end)
│ ├── graph.py # Knowledge-graph builder
│ ├── search.py # BM25 + graph search + refusal gates
│ ├── embedding.py # Optional local embedding index (RRF fusion)
│ ├── llm_enrich.py # Optional LLM draft notes (conf=LLM, human-reviewed)
│ ├── mcp.py # MCP stdio server (7 read-only tools incl. kg_context; kg_feedback behind --enable-write; hot reload)
│ ├── store.py # Evidence store (immutable generations)
│ ├── knowledge.py # Knowledge base (notes/claims/review)
│ └── ...
├── benchmarks/ # Five-system comparison suite + frozen protocol
├── tests/ # Contract tests (every feature has negative cases)
├── specs/ # Requirements, acceptance cases, task manifests
└── docs/ # Documentation
```
## Documentation
| Document | Description |
|---|---|
| [docs/README.md](docs/README.md) | Documentation index |
| [docs/knowledge-graph.md](docs/knowledge-graph.md) | **Knowledge-graph model reference** — node/edge taxonomy, evidence store, time model, query flow |
| [docs/evolution.md](docs/evolution.md) | **Maturity gaps & evolution plan** |
| [docs/roadmap.md](docs/roadmap.md) | Production roadmap |
| [docs/architecture.md](docs/architecture.md) | Architecture details |
| [docs/clients.md](docs/clients.md) | MCP client integration guide |
| [specs/benchmark.md](specs/benchmark.md) | Benchmark protocol |
## Known Limitations
- **Evaluation status**: 38/49 verified(2026-10-28:AC-R12-02 以当前源码消融重验、AC-F1-C1-01/02 以当前源码真实 Claude 会话重验;AC-R10-02 维持 implementing 待 24h 负载); remaining 11 are external — 3 clients blocked (Codex account model lockout, ZCode awaiting a user session, DSH binary/balance), the 24h mixed-load + real-migration drill, and the frozen four-competitor confirmation. All benchmark numbers remain same-session developer evaluations; `make release-check` fails by design until the confirmation run
- **Cross-lingual gap (mostly closed)**: pure-BM25 could not match Chinese queries to English content; the optional embedding lane + doc chunking lifted public-corpus retrieval from 50→70/140 — answer-layer reruns still pending
- **Same-name methods**: distinguished by class and parameter-type signature. A call edge is taken from the enclosing method body. Bare calls on a simple class name resolve only inside that file
- **Workspace overlays**: `rules.json` in the output directory can name extra provider/consumer annotations. `domimap.seeds.json` there overrides domain names and merges synonym lists. Neither file is required
- **Scale**: a synthetic 200 one-class-repo gate is in `scripts/scale_gate.py`. It does not measure a real multi-module Java system. `make release-check` still fails until the frozen four-competitor confirmation exists
- **Source updates**: incremental updates are manual (`domimap update`; no file watcher yet). Clean tracked Git files are signed `git:<blob id>`; dirty and untracked files stay content sha256. An older sha256-only manifest rebuilds once on the next update
- **Platform**: fully tested on macOS + Linux CI; Windows untested
## License
MIT License. See [LICENSE](LICENSE).
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues