Technical deep-dive into @zabaca/lattice - a human-initiated, AI-powered knowledge graph CLI for markdown documentation.

Overview

Lattice extracts entities and relationships from markdown documents and syncs them directly to a DuckDB database, enabling semantic search across documentation. No frontmatter required - your markdown files stay clean.

┌─────────────────────────────────────────────────────────────────┐
│ Lattice CLI (@zabaca/lattice) │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌────────────────┐ │
│ │ Markdown │────▶│ Lattice │────▶│ DuckDB │ │
│ │ Docs │ │ Sync │ │ (embedded) │ │
│ │ ~/.lattice/ │ │ │ │ │ │
│ └──────────────┘ │ - Parse │ │ - Nodes table │ │
│ │ - Extract │ │ - Rels table │ │
│ │ - Dedupe │ │ - HNSW index │ │
│ └──────────────┘ └───────┬────────┘ │
│ │ │ │
│ ▼ │ │
│ ┌──────────────┐ │ │
│ │ Voyage AI │◀────────────┘ │
│ │ Embeddings │ Semantic Search │
│ └──────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘

Technology Stack

LayerTechnologyPurpose
CLI Frameworknest-commanderCommand parsing and execution
ApplicationNestJSDependency injection, modules
ValidationZodSchema validation
DatabaseDuckDBEmbedded graph + vector storage
Vector SearchDuckDB VSSHNSW index with cosine similarity
EmbeddingsVoyage AISemantic search vectors (voyage-3-lite)
RuntimeBunFast JavaScript runtime

Key Architecture Decisions

  • Embedded database: DuckDB requires zero external dependencies (no Docker, no Redis)
  • No frontmatter: Entities extracted directly to database, markdown files stay clean
  • Single file storage: All data in ~/.lattice/lattice.duckdb
  • HNSW vector indexing: Fast approximate nearest neighbor search

Project Structure

lattice/
├── src/
│ ├── commands/ # CLI command implementations
│ │ ├── sync.command.ts # lattice sync
│ │ ├── status.command.ts # lattice status
│ │ ├── query.command.ts # lattice search, rels, sql
│ │ ├── ontology.command.ts # lattice ontology
│ │ ├── init.command.ts # lattice init
│ │ ├── extract.command.ts # lattice extract (debug)
│ │ └── migrate.command.ts # lattice migrate (v1→v2)
│ │
│ ├── sync/ # Document synchronization
│ │ ├── sync.service.ts # Main sync orchestration
│ │ ├── manifest.service.ts # Change detection (hashes)
│ │ ├── document-parser.service.ts
│ │ ├── entity-extractor.service.ts # AI entity extraction
│ │ ├── cascade.service.ts # Relationship impact analysis
│ │ ├── ontology.service.ts # Schema introspection
│ │ └── database-change-detector.service.ts
│ │
│ ├── graph/ # DuckDB operations
│ │ ├── graph.service.ts # SQL query execution
│ │ └── graph.types.ts # Type definitions
│ │
│ ├── embedding/ # Vector embeddings
│ │ ├── embedding.service.ts
│ │ └── providers/
│ │ ├── voyage.provider.ts # Production
│ │ ├── openai.provider.ts # Alternative
│ │ └── mock.provider.ts # Testing
│ │
│ ├── schemas/ # Zod schemas
│ │ ├── entity.schemas.ts
│ │ ├── graph.schemas.ts
│ │ └── config.schemas.ts
│ │
│ ├── pure/ # Pure functions (testable)
│ │ ├── hashing.ts
│ │ ├── embedding-text.ts
│ │ └── validation.ts
│ │
│ ├── utils/
│ │ ├── paths.ts # ~/.lattice/ path utilities
│ │ └── frontmatter.ts # Legacy frontmatter parsing
│ │
│ ├── app.module.ts # NestJS root module
│ └── main.ts # Application entry
├── commands/ # Claude Code slash commands
│ ├── research.md
│ └── graph-sync.md
└── dist/ # Build output

Database Schema

Nodes Table

CREATE TABLE nodes (
label VARCHAR NOT NULL, -- Entity type: Document, Technology, etc.
name VARCHAR NOT NULL, -- Unique identifier
properties JSON, -- Additional metadata (description, title, etc.)
embedding FLOAT[512], -- Vector for semantic search
PRIMARY KEY(label, name)
);
-- HNSW index for vector similarity search
CREATE INDEX nodes_hnsw_idx ON nodes
USING HNSW (embedding)
WITH (metric = 'cosine');

Relationships Table

CREATE TABLE relationships (
source_label VARCHAR NOT NULL,
source_name VARCHAR NOT NULL,
relation_type VARCHAR NOT NULL, -- REFERENCES or APPEARS_IN
target_label VARCHAR NOT NULL,
target_name VARCHAR NOT NULL,
properties JSON,
PRIMARY KEY(source_label, source_name, relation_type, target_label, target_name)
);

Entity Labels

LabelDescriptionExample
DocumentMarkdown files (auto-created)/home/user/.lattice/docs/topic/file.md
TopicResearch subjects”Machine Learning”
TechnologyTools, frameworks, languages”TypeScript”, “React”
ConceptAbstract ideas, patterns”GraphRAG”, “Microservices”
ToolSpecific software tools”Lattice”, “Docker”
ProcessWorkflows, procedures”Entity Extraction”
PersonPeople”Tim Davis”
OrganizationCompanies, teams”Anthropic”
LocationPlaces, paths”~/.lattice/docs/“

Relationship Types

TypeCreated ByDescription
REFERENCESAI extractionSemantic connection between entities
APPEARS_INAuto-generatedLinks entity to source document

Sync Workflow

Change Detection

Lattice tracks document changes using content hashes stored in the database:

-- Hash tracking in nodes table properties
SELECT name, properties->>'contentHash' as hash
FROM nodes
WHERE label = 'Document';

Sync Phases

Phase 1: Detect changes (compare file hashes vs stored hashes)
Phase 2: Parse changed documents
Phase 3: Extract entities using Claude Code (via /graph-sync)
Phase 4: Deduplicate entities across documents
Phase 5: Upsert nodes with embeddings
Phase 6: Create APPEARS_IN relationships
Phase 7: Create REFERENCES relationships

Entity Deduplication

When the same entity appears in multiple documents, Lattice merges them:

  • Keeps the longest description
  • Tracks all source document paths
  • Single node with multiple APPEARS_IN relationships

CLI Commands

CommandDescription
lattice initInstall Claude Code slash commands
lattice syncSync documents to graph
lattice statusShow pending changes
lattice search <query>Semantic search
lattice sql <query>Raw SQL queries
lattice rels <name>Show relationships for entity
lattice ontologyShow derived schema
lattice extract <file>Debug entity extraction
lattice migrateMigrate from v1 to v2

Sync Options

Terminal window
lattice sync [paths...] # Sync specific paths or all
lattice sync --force # Force re-sync (rebuilds graph)
lattice sync --dry-run # Preview changes

How It Works

  1. User query is embedded using Voyage AI (voyage-3-lite)
  2. DuckDB VSS extension performs HNSW approximate nearest neighbor search
  3. Results ranked by cosine similarity

SQL Example

-- Find similar nodes using vector search
SELECT name, label,
array_cosine_similarity(embedding, $query_embedding) as score
FROM nodes
WHERE embedding IS NOT NULL
ORDER BY score DESC
LIMIT 20;

Claude Code Integration

Lattice is designed as a Claude Code-first tool.

Slash Commands

CommandDescription
/research [topic]AI-assisted research workflow
/graph-syncBatch entity extraction + sync

/research Workflow

1. Search existing docs via `lattice search`
2. Present findings to user
3. Ask if new research needed
4. If yes: WebSearch → Create docs
5. Remind user to run /graph-sync

/graph-sync Workflow

1. Run `lattice status` to find modified docs
2. For each modified doc:
- Extract entities using Claude
- Write directly to database
3. Run `lattice sync` to finalize
4. Report results

Design Philosophy

  1. Human-initiated: Claude Code executes, but human approves
  2. AI-powered extraction: LLM identifies entities from content
  3. No frontmatter: Database-first, clean markdown files
  4. Incremental sync: Only process changed documents
  5. Embedded database: Zero external dependencies

Configuration

Environment Variables

VariableDescriptionDefault
VOYAGE_API_KEYVoyage AI API keyrequired
EMBEDDING_DIMENSIONSVector dimensions512

Storage Location

All data stored in ~/.lattice/:

~/.lattice/
├── docs/ # Markdown documentation
├── lattice.duckdb # Graph database
├── .sync-manifest.json # Sync state (legacy, migrating to DB)
└── .env # API keys

Sources

  1. Lattice GitHub Repository
  2. DuckDB Documentation
  3. DuckDB VSS Extension
  4. NestJS Documentation
  5. Voyage AI Documentation