2dph

module
v0.24.10 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 23, 2026 License: MIT

README

2dph — deductionphile

Go Tests Latest Release GitHub Stars

An evidence-first brain. Facts need two independent sources, or they are (not confirmed).

2dph is a single embedded knowledge graph (LadybugDB) with native HNSW vector + BM25 full-text indexes. Search is deduction: confirmed facts first, supporting info second, web-search as the independent second source when the local graph cannot confirm.

What's in 2dph today

  • Single embedded store — one file var/kb.lbug (LadybugDB).
  • Native property graph + Cypher.
  • Native HNSW (vectors, 256-dim model2vec) + BM25 FTS.
  • Hybrid search — facts → info → web.
  • Graph-hop (--hop N: File → Commit → Person).
  • ACID transactions — facts + info in one transaction.
  • Incremental write + bulk rebuild.
  • DuckDB as auxiliary (D22 / OQ3): quantiles, JSONL stats via duckdb-go in-process — a helper tool, not the primary store.

Run it: docs/runbook.md. Design: docs/design.md. Docs index: docs/README.md.

Tool layout (D14)

Every command lives at bin/{subject}/{method}.go — one method per file, shared logic in internal/. The filename is the invocation, and the subject is the domain area it acts on:

Subject Method Does
bin/brain search.go deduction search (facts → info → web)
bin/brain index.go / add.go bulk rebuild / incremental write
bin/brain serve.go HTTP API + OpenAPI/MCP
bin/facts extract.go / audit.go / crm.go 2-source pairing, confidence, CRM proof
bin/rules book.go rule-source extraction (PDF → gitignored chapter text)
bin/mail sync.go / import.go / ocr.go mail ETL (Gmail/OO/M365)
bin/web search.go SearXNG second source
bin/git import.go commit history leafs
bin/chat sync.go / import.go / apply.go conversations
scripts/stack start / status / stop compose dispatcher

Go methods are executable (go run shebang); a few are thin bash launchers (bin/chat, scripts/db/psql-yq). Shell completions for all tools (D23) come from bin/shell/complete.go — see the runbook. Keep it one-command-one-file so the surface stays deductive: you read the path, you know the tool.

bin/cgo is the CGO toolchain, not CI/CD: zig (the pinned Zig compiler), zcc / zc++ (wrappers). Ladybug and tokenizer C libraries are compiled with zig cc (D21), so brain read/write Go binaries link CGO without a system gcc. CI/CD lives separately in .github/workflows/ci.yml.

Architecture

graph LR
    subgraph src["Sources"]
        direction TB
        DOC["documents"]
        MAIL["mail"]
        CHAT["chats"]
        CONTACT["contacts"]
        GIT["git history"]
    end

    subgraph etl["Adapters → leafs"]
        direction TB
        SPLIT["markdown/split-leaf"]
        MAILI["mail/sync · mail/import"]
        CHATI["chat/sync · chat/import"]
        CONV["contact/list"]
        GITI["brain/import-git"]
    end

    subgraph store["Embedded store — Ladybug (one kb.lbug)"]
        ROOTS["roots: facts | info<br/>one ACID transaction"]
        IDXN["HNSW vectors + BM25 FTS<br/>(model2vec embeddings)"]
        GRAPH["property graph · Cypher<br/>File→Commit→Person hops"]
    end

    subgraph read["Deduction read path"]
        SRCH["brain/search<br/>facts → info → web"]
        SERVE["brain/serve<br/>HTTP · OpenAPI · MCP"]
    end

    subgraph gate["Evidence gate"]
        EXTR["facts/extract<br/>2-source pairing"]
        AUD["facts/audit-db<br/>confidence + staleness"]
    end

    WEB["web-search<br/>independent 2nd source"]
    AGENT["agents · operators"]

    DOC --> SPLIT
    MAIL --> MAILI
    CHAT --> CHATI
    CONTACT --> CONV
    GIT --> GITI

    SPLIT --> ROOTS
    MAILI --> ROOTS
    CHATI --> ROOTS
    CONV --> ROOTS
    GITI --> GRAPH
    EXTR --> ROOTS
    IDXN --- ROOTS
    GRAPH --- ROOTS

    ROOTS --> SRCH
    SRCH <-.-> WEB
    SRCH --> SERVE
    SERVE --> AGENT
    AUD --> ROOTS

Reads are deduction: confirmed facts first, supporting info second, web-search as the independent second source when the local graph cannot confirm. Writes never bypass the store's single transaction.

The method

Every assertion is Who / What / How / Where / When + evidence + confidence, mirroring the detective method: ≥2 independent sources confirm a fact; conflicting sources or a single source → hypothesis → (not confirmed).

root meaning used for answers
facts assertions backed by ≥2 sources (confirmed) yes, with evidence links
info descriptive/narrative leafs (how-tos, notes) context only, marked (not confirmed)
bin/brain/search.go "Matrix federation over HTTPS"   # facts → info → web
bin/brain/search.go "onlyoffice postgres" --root facts
bin/brain/search.go "where is cs-lexicon" --json | yq '.'
bin/brain/search.go "upstream flag" --no-web         # local graph only
bin/brain/get.go <id> --body                         # full chunk on demand
bin/brain/stats.go                                   # index health
bin/brain/eval.go                                    # recall@5 gate

--hop N walks File/Commit/Person from each hit (max 3). Search is bin/brain/search.go.

Git history is read with go-git (no git binary):

bin/brain/import-git.go --json --limit 100              # commit leafs for this repo
bin/brain/import-git.go --root "$PROJECTS_ROOT" --json  # one pass per .git under root

Conversion only. Graph write (File-[:HAS_VERSION]->Commit-[:AUTHORED]->Person) stays with bin/brain/index.go.

Web search (second independent source) goes through SearXNG. Empty results mean throttled, not “nothing exists”:

bin/web/search.go "LadybugDB vector index" --json
# Optional local instance (skip if BRAIN_SEARCH_URL already points at one):
# SEARXNG_SECRET=$(openssl rand -hex 32) docker compose --profile searxng up -d

Mail is a first-class corpus (retrievable through the same search):

bin/mail/sync.go --source onlyoffice,gmail --workers 8 --out var/corpus/mail  # raw sync (Go)
bin/mail/sync.go --source m365 --env ~/.config/brain/mail.env          # Microsoft 365 Graph
scripts/stack/start-mail-sync                                              # compose ETL (300s; no auto-rebuild)
bin/mail/import.go --from-raw var/corpus/mail                                  # JSON → markdown
bin/brain/add.go --text T --root facts --source "a.md x b.md"
bin/brain/index.go --rebuild --with-facts --with-chats                  # facts extract + chats md
bin/brain/index.go --rebuild                                            # rebuild brain (incl. mail)
bin/brain/search.go "invoice from last week"                            # same search over mail leafs

Storage

  • LadybugDB — single var/kb.lbug, Cypher + HNSW + BM25, embedded. Read tools (get / stats / eval) are Go + Zig CGO (bin/cgo/zcc). Incremental write is bin/brain/add.go; bulk rebuild is Compose profile index (bin/brain/index.go --rebuild).
  • potion-multilingual-128M — 256-dim embeddings (Go/Ladybug, CPU, no Ollama) runtime dependency.
  • facts and info split by root but written in the same transaction.

Ladybug 0.19 DROP INDEX warning: docs/runbook.md.

Tooling conventions

bin/{subject}/{method}.go — self-describing: shebang on line 1, usage comment from line 2. Shared code in internal/. YAML default output, --json for machines. Tests gate every commit. HTTP: bin/brain/serve.go calls internal/brain in-process (/health /search /get /stats /audit /ingest /openapi.json /mcp).

Development

See the portable runbook: docs/runbook.md.

bin/facts/audit.go self
go test ./...

Docker (optional, cached model + var volumes):

scripts/stack/start                                # brain HTTP/MCP :8630
scripts/stack/start-assistant                      # + qwen3.5:9b + PicoClaw agent
scripts/stack/status
scripts/stack/stop
docker compose up -d brain                     # API (Zig CGO serve :8630)
docker compose --profile index run --rm index  # Go Ladybug rebuild (zig cgo)
docker compose --profile picoclaw up brain-mcp # MCP on 127.0.0.1:8630
docker compose --profile reasoner up -d reasoner  # CPU Ollama 127.0.0.1:11435
docker compose up brain-watch                  # auto re-index on change

eSlider DevOps engineer practice: ops, OnlyOffice, and mail feed the facts root through bin/facts/extract (two-source pairing).

  • go-second-brain — the earlier Neo4j + Qdrant + Matrix RAG brain
  • agent-skills — upstream skills (web-search, postgres, …) that 2dph integrates
  • detective method — the two-source method

Work board (issues): epic #16 on git.produktor.io/eSlider/2dph/issues. PRs and CI: GitHub eSlider/2dph.

See PLAN.md for decisions, docs/roadmap.md for the gap to v1, and v2 open questions.

Directories

Path Synopsis
bin
brain command
Commands in this directory are shebang mains (search.go, serve.go, index.go, get.go, stats.go, eval.go, watch.go), each behind an exclusive build tag.
Commands in this directory are shebang mains (search.go, serve.go, index.go, get.go, stats.go, eval.go, watch.go), each behind an exclusive build tag.
chat command
Commands in this directory are shebang mains (sync.go, import.go, facts.go, apply.go), each behind an exclusive build tag so `go build ./bin/chat` does not see two mains.
Commands in this directory are shebang mains (sync.go, import.go, facts.go, apply.go), each behind an exclusive build tag so `go build ./bin/chat` does not see two mains.
cron command
usr/bin/env go run "$0" "$@"; exit
usr/bin/env go run "$0" "$@"; exit
facts command
usr/bin/env bash -c 'exec go run "$0" "$@"' "$0" "$@"; exit
usr/bin/env bash -c 'exec go run "$0" "$@"' "$0" "$@"; exit
mail command
usr/bin/env go run "$0" "$@"; exit bin/mail/sync.go - async download of OnlyOffice, Gmail and M365 mail to var/corpus/mail/.
usr/bin/env go run "$0" "$@"; exit bin/mail/sync.go - async download of OnlyOffice, Gmail and M365 mail to var/corpus/mail/.
mail/watch command
usr/bin/env go run "$0" "$@"; exit
usr/bin/env go run "$0" "$@"; exit
markdown command
Commands in this directory are shebang mains (import.go), tagged so `go build ./bin/markdown` does not see two mains.
Commands in this directory are shebang mains (import.go), tagged so `go build ./bin/markdown` does not see two mains.
onlyoffice command
Commands in this directory are shebang mains (import-contact.go, reconcile-contact.go, …), each behind an exclusive build tag so `go build ./bin/onlyoffice` does not see two mains.
Commands in this directory are shebang mains (import-contact.go, reconcile-contact.go, …), each behind an exclusive build tag so `go build ./bin/onlyoffice` does not see two mains.
postgres command
Commands in this directory are shebang mains (query.go).
Commands in this directory are shebang mains (query.go).
reasoner command
Commands in this directory are shebang mains (bakeoff.go).
Commands in this directory are shebang mains (bakeoff.go).
runner command
usr/bin/env go run "$0" "$@"; exit
usr/bin/env go run "$0" "$@"; exit
semver command
usr/bin/env go run "$0" "$@"; exit
usr/bin/env go run "$0" "$@"; exit
shell command
usr/bin/env go run "$0" "$@"; exit
usr/bin/env go run "$0" "$@"; exit
stack command
usr/bin/env go run "$0" "$@"; exit
usr/bin/env go run "$0" "$@"; exit
web command
usr/bin/env go run "$0" "$@"; exit
usr/bin/env go run "$0" "$@"; exit
internal
address
Package address implements canonical content URL addressing for the ETL layer (AGENTS #100).
Package address implements canonical content URL addressing for the ETL layer (AGENTS #100).
brain
Потоковая/чанкованная запись корпуса (issue #237): корпус не накапливается в одном срезе — CountCorpus считает leafs, WriteCorpusChunked стримит источники и пишет чанками по size.
Потоковая/чанкованная запись корпуса (issue #237): корпус не накапливается в одном срезе — CountCorpus считает leafs, WriteCorpusChunked стримит источники и пишет чанками по size.
brain/bench
Package bench implements the A/B search benchmark harness (issue #202): a fixed golden-set of queries is run through a search implementation and scored on latency (p50/p95/mean), recall@5/@10 and CPU/RSS.
Package bench implements the A/B search benchmark harness (issue #202): a fixed golden-set of queries is run through a search implementation and scored on latency (p50/p95/mean), recall@5/@10 and CPU/RSS.
brain/rank
Package rank is the cgo-free ranking and CLI parsing for brain search.
Package rank is the cgo-free ranking and CLI parsing for brain search.
canon
Package canon is the conversation-canon evidence layer for the sync-ETL pipeline (epic #88, issue #99).
Package canon is the conversation-canon evidence layer for the sync-ETL pipeline (epic #88, issue #99).
config
Package config loads the typed 2dph configuration.
Package config loads the typed 2dph configuration.
contract
Package contract — единый контракт записи leaf в Ladybug (2dph).
Package contract — единый контракт записи leaf в Ladybug (2dph).
corpus
Package corpus — адаптеры источников корпуса (P-9.3), cgo-free.
Package corpus — адаптеры источников корпуса (P-9.3), cgo-free.
corpuswatch
Package watch polls corpus directories for changes and re-runs brain/index.
Package watch polls corpus directories for changes and re-runs brain/index.
cron
Package cron implements periodic extraction → brain ingest daemons.
Package cron implements periodic extraction → brain ingest daemons.
docbody
Package docbody enriches gator kind=document Leafs with the text of the PDF body (T12, #310).
Package docbody enriches gator kind=document Leafs with the text of the PDF body (T12, #310).
docgraph
Package docgraph — коннектор gator kind=document → searchable Leaf (C1 #117, ADR-0013).
Package docgraph — коннектор gator kind=document → searchable Leaf (C1 #117, ADR-0013).
dockerctl
Package dockerctl is a minimal Docker Engine API client over the local unix socket, enough for the index-sync cycle to quiesce and restart the compose brain service: find one container by compose labels, stop it, start it, inspect its running/health state.
Package dockerctl is a minimal Docker Engine API client over the local unix socket, enough for the index-sync cycle to quiesce and restart the compose brain service: find one container by compose labels, stop it, start it, inspect its running/health state.
docpipe
Package docpipe implements the hybrid PDF handler PoC (epic #219, issue #223): a pdftotext -layout fast path for text-layer PDFs plus the warm liteparse JSON path (docker compose exec via internal/research.Runner) for scans/complex documents, with table reconstruction from text_items geometry (y-buckets → rows, x-sort → cells).
Package docpipe implements the hybrid PDF handler PoC (epic #219, issue #223): a pdftotext -layout fast path for text-layer PDFs plus the warm liteparse JSON path (docker compose exec via internal/research.Runner) for scans/complex documents, with table reconstruction from text_items geometry (y-buckets → rows, x-sort → cells).
etl
Registry maps stable handler keys ("mail", "git", "markdown", "facts", …) to a Handler.
Registry maps stable handler keys ("mail", "git", "markdown", "facts", …) to a Handler.
facts
Package facts is cgo-free evidence rules: D16 contradictions (Adjudicate/CheckFactRow) and L-9.3 formal URL checks (CheckFormal/CanonicalURL, identity/contradiction/excluded_middle).
Package facts is cgo-free evidence rules: D16 contradictions (Adjudicate/CheckFactRow) and L-9.3 formal URL checks (CheckFormal/CanonicalURL, identity/contradiction/excluded_middle).
gitgraph
Package gitgraph — коннектор git-истории → граф 2dph (L-9.4 #233).
Package gitgraph — коннектор git-истории → граф 2dph (L-9.4 #233).
gitlog
Package gitlog reads commit history with go-git (no git binary).
Package gitlog reads commit history with go-git (no git binary).
incubator
Package incubator imports legacy mail corpora (Thunderbird profile dumps, .eml trees) into a docker-mailserver incubator mailbox via doveadm save (issue #252 / epic #250).
Package incubator imports legacy mail corpora (Thunderbird profile dumps, .eml trees) into a docker-mailserver incubator mailbox via doveadm save (issue #252 / epic #250).
indexsync
Corpus flag/env plumbing for the index-loop CLI (#317): the skills tree is indexed by brain-index --corpus as part of the periodic cycle.
Corpus flag/env plumbing for the index-loop CLI (#317): the skills tree is indexed by brain-index --corpus as part of the periodic cycle.
items
Package items implements granular content splitting (AGENTS #100): an html/markdown body is decomposed BEFORE insertion into a typed tree of Items (paragraph / heading / table / row / cell / image / link / page).
Package items implements granular content splitting (AGENTS #100): an html/markdown body is decomposed BEFORE insertion into a typed tree of Items (paragraph / heading / table / row / cell / image / link / page).
mailconv
Type-handler registry for mail attachments, keyed by MIME type + extension.
Type-handler registry for mail attachments, keyed by MIME type + extension.
mailgraph
Package mailgraph — коннектор gator kind=mail → граф 2dph (D-1.3 #260).
Package mailgraph — коннектор gator kind=mail → граф 2dph (D-1.3 #260).
mailsync
Package synccmd wires the sync library to a CLI: reads .env, parses flags, picks sources, prints stats.
Package synccmd wires the sync library to a CLI: reads .env, parses flags, picks sources, prints stats.
network
Package network — сеть связей L-9.5 (#234): «с кем и через кого» из mail+commits поверх готового графа (D-1 #257: Message/Person/рёбра; L-9.4 #233: Commit/Person/AUTHORED).
Package network — сеть связей L-9.5 (#234): «с кем и через кого» из mail+commits поверх готового графа (D-1 #257: Message/Person/рёбра; L-9.4 #233: Commit/Person/AUTHORED).
ocr
Package ocr runs Tesseract (eng+deu) on images and scanned PDFs.
Package ocr runs Tesseract (eng+deu) on images and scanned PDFs.
oohtml
Package oohtml builds the branded produktor.io HTML mail template and runs the render-check gate that blocks sending until the draft round-trips with paragraphs, the cid-embedded logo and the signature intact.
Package oohtml builds the branded produktor.io HTML mail template and runs the render-check gate that blocks sending until the draft round-trips with paragraphs, the cid-embedded logo and the signature intact.
ooimport
Package ooimport — коннектор сети связей → OnlyOffice CRM (N-1.2 #269, epic #267).
Package ooimport — коннектор сети связей → OnlyOffice CRM (N-1.2 #269, epic #267).
research
Package research holds the liteparse integration primitives shared by the A/B harness (bin/research/ab.go) and the struct-data ETL tool (bin/research/convert.go).
Package research holds the liteparse integration primitives shared by the A/B harness (bin/research/ab.go) and the struct-data ETL tool (bin/research/convert.go).
rules
Package rules — типизированный каталог правил вывода (epic #324).
Package rules — типизированный каталог правил вывода (epic #324).
runner
Package runner wires the bounded sync-ETL pipeline (#98):
Package runner wires the bounded sync-ETL pipeline (#98):
selector
Package selector implements the point-retrieval selector mini-language (AGENTS #100): a DOM/jQuery-like structural selector over a typed Item tree.
Package selector implements the point-retrieval selector mini-language (AGENTS #100): a DOM/jQuery-like structural selector over a typed Item tree.
skills
Package skills validates that in-repo skills only reference tools that exist.
Package skills validates that in-repo skills only reference tools that exist.
source
Package source implements the unified sync-ETL Source adapter layer (#97).
Package source implements the unified sync-ETL Source adapter layer (#97).
websearch
Package websearch is the SearXNG client used as the second independent source.
Package websearch is the SearXNG client used as the second independent source.
pkg
brainclient
Package brainclient — сервисный клиент read-контракта brain (P-9.5, docs/brain/read-contract.md): тонкая HTTP-обёртка над search/get/stats/ audit с typed-ответами internal/contract (JSON-схема P-9.4) и «гейтом facts» (gate.go) — клиент никогда не выдаёт не подтверждённый ответ как подтверждённый факт.
Package brainclient — сервисный клиент read-контракта brain (P-9.5, docs/brain/read-contract.md): тонкая HTTP-обёртка над search/get/stats/ audit с typed-ответами internal/contract (JSON-схема P-9.4) и «гейтом facts» (gate.go) — клиент никогда не выдаёт не подтверждённый ответ как подтверждённый факт.
brainclient/cli
Package cli — CLI bin/brain/client.go: сервисный клиент read-контракта brain (P-9.5).
Package cli — CLI bin/brain/client.go: сервисный клиент read-контракта brain (P-9.5).
cli
Package cli is the shared flaggy wrapper (D23).
Package cli is the shared flaggy wrapper (D23).
duckdb
Package duckdb runs in-process DuckDB for columnar aggregates.
Package duckdb runs in-process DuckDB for columnar aggregates.
httpapi
Package httpapi serves the 2dph brain over HTTP.
Package httpapi serves the 2dph brain over HTTP.
utils
Package utils holds small, dependency-free helpers shared across pkg/ and internal/.
Package utils holds small, dependency-free helpers shared across pkg/ and internal/.
test
stress command
usr/bin/env go run "$0" "$@"; exit
usr/bin/env go run "$0" "$@"; exit
system command
usr/bin/env go run "$0" "$@"; exit
usr/bin/env go run "$0" "$@"; exit

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL