npm.io
0.2.1 • Published yesterdayCLI

@yasnikoff/docdog

Licence
MIT
Version
0.2.1
Deps
12
Size
886 kB
Vulns
0
Weekly
0

docdog

Context management for AI agents. Your project's decisions, specs, and notes live as markdown files with YAML frontmatter — docdog gives agents a fast retrieval surface over them: hybrid search, a relationship graph, and eight MCP tools. No services, no migrations, no lock-in.

Files are the source of truth. The index is a disposable local SQLite cache (.docdog/cache/, gitignored), rebuilt from disk by docdog index. Deleting the cache is always safe. Deleting docdog leaves you with a folder of readable markdown.

Why

Agents re-derive project context every session — grepping for decisions that are recorded somewhere, re-asking questions the repo already answers, missing the constraint that made yesterday's design choice. Docdog turns the corpus of decisions/specs/notes into something an agent can actually query.

Measured on docdog's own 250-record corpus (40 frozen queries with gold answers, single-shot, no reformulation on either side):

Hit@1 Hit@5 MRR@10 median tokens to locate the answer
docdog hybrid search 80% 95% 0.871 ~143
grep, generously ranked 30% 63% 0.446
grep, raw transcript 3% 5% 0.047 ~6,500

Honest caveats: the corpus is small and self-describing (agent-authored titles and descriptions do real lifting), and the gold judgments were made by the system's builder. Method, harness, and the frozen query set live in tests/eval/; the full analysis is OBS-010.

How it works

  • A record is a markdown section with frontmatter: id, title, collection, status, description, and a relationships: block.
  • The graph is frontmatter. Every relationship edge is born in the source record's relationships: block — the cache's edge table is purely derived. git diff shows you graph changes.
  • The cache is one embedded SQLite file: FTS5 for BM25 keyword search, in-process embeddings (ONNX, no API calls) for the vector leg, reciprocal-rank fusion to merge them.
  • No migrations, ever. Schema change? The cache drops and rebuilds from disk.
  • Zero service dependencies. Node 20+ is the whole install story. First docdog index downloads the embedding model once.

A record looks like this (collection: must be one your project registers — see vertex_collections in .docdog/config.yaml):

---
id: DD-014
title: "Auth tokens move to httpOnly cookies"
collection: decisions
status: current
description: "JWTs leave localStorage; the API gains /refresh. XSS was the driver."
relationships:
  - supersedes: DD-009
    context: "localStorage tokens were XSS-exposed"
---

# DD-014: Auth tokens move to httpOnly cookies

Ordinary markdown body...

Quickstart

npm install -g @yasnikoff/docdog

# --template structured registers decisions/requirements/principles/…;
# the default `minimal` registers only notes + concepts, and a record
# whose collection is not registered is skipped at index time.
docdog init --name my-project --template structured
docdog index                    # build the cache from your scan paths
docdog search "why did we drop the legacy auth flow"
docdog serve                    # MCP server (init wires .mcp.json for you)

Point your agent at the MCP server and it gets the full tool surface. Records are created by the agent (via MCP) or by hand — write markdown, run docdog index, done. Deletion is rm + docdog index; files and git are the archive.

Using docdog from Claude Cowork (desktop app)

docdog init wires .mcp.json for Claude Code. The Cowork desktop app doesn't read a project's .mcp.json — register docdog serve in the app's own config instead, and it proxies the tools into your session. See docs/cowork-mcp-setup.md.

Indexing offline

The first docdog index downloads the embedding model (nomic-ai/nomic-embed-text-v1, ~550 MB) from huggingface.co. On a machine that can't reach it, drop the model files in yourself — docdog looks there before the network:

.docdog/models/nomic-ai/nomic-embed-text-v1/
  onnx/model.onnx
  config.json
  tokenizer.json
  tokenizer_config.json

Copy them from any machine that has already indexed (they land in node_modules/@huggingface/transformers/.cache/) or from the model's Hugging Face page. The embed.provider: ollama alternative in .docdog/config.yaml needs a reachable ollama server, so it is not an offline answer by itself.

MCP tools

Tool What it does
docdog_search hybrid retrieval (BM25 + vector, rank fusion)
docdog_get fetch a record by id
docdog_traverse walk the relationship graph from a record
docdog_relate add an edge — patches the source file's frontmatter
docdog_create create a record file at a caller-supplied path
docdog_update patch a record's frontmatter/body
docdog_index rebuild/refresh the cache
docdog_status corpus and cache stats

CLI

Every MCP tool above has a CLI counterpart wherever the shell can express its inputs, so an agent without MCP is not a second-class caller. The two exceptions are docdog_create and docdog_update: they take a markdown body, which is the one input shell quoting mangles. From a shell you write the file and run docdog index — the files are the source of truth, so that is the same operation, not a workaround.

docdog init            # create .docdog/, config, MCP wiring
docdog index           # (re)index scan_paths into the embedded cache
docdog search <query>  # hybrid search from the terminal
docdog get <id>        # print a record
docdog traverse <id>   # walk the relationship graph  --depth, --direction
docdog relate <a> <b>  # record an edge — patches a's frontmatter  --type, --context
docdog status          # corpus and cache stats — and any id two files claim
docdog suggest-edges   # report undeclared id mentions as edge candidates, for review
docdog renumber <old> <new>  # rename an id and rewrite every inbound edge  --prose, --rename-file
docdog serve           # start the MCP server
docdog add <file>      # stamp frontmatter onto raw markdown
docdog split <file>    # split a multi-section file into one-file-per-section
docdog gc              # evict stale embedding-cache rows
docdog templates       # list/inspect record templates
docdog run <name>      # run a project script from .docdog/scripts/
docdog skill install   # emit agent-facing navigation skills

Every read command takes --json.

docdog init also installs a git merge driver for the relationships: block. Two branches each adding an edge to the same record is a set union, but git diffs lines and calls it a conflict — the driver unions them, and still conflicts loudly on anything that needs a judgment call.

Design stance

Docdog's code is strictly mechanical — ranking, indexing, file surgery. Semantic judgment (what a record means, where it belongs, what relates to what) stays with the agent and the user. That principle and the others are recorded in specs/principles/, and the whole design history is in specs/decisions/ — docdog manages its own specs, so this repo doubles as the living demo. Point docdog search at it and ask it why it exists.

Status

Pre-1.0, self-hosted daily. Node ≥ 20; Windows, macOS, Linux. MIT.

Keywords