Skip to content

Latest commit

 

History

History
201 lines (160 loc) · 9.46 KB

File metadata and controls

201 lines (160 loc) · 9.46 KB
document_id doc.system-architecture
last_verified 2026-03-06
tokens_estimate 950
tags
architecture
system
overview
anchors
id summary
overview
Desktop Next.js + Electron app; SQLite, agentic-flow, RuVector
id summary
data-model
Project → Workflow → Activity → Card; knowledge items; orchestration entities
id summary
data-flow
Chat → actions → SQLite; Build → clone → dispatch → feature branch
id summary
boundaries
Planning LLM cannot build; build agents cannot merge; humans gate all merges
ttl_expires_on

System Architecture — As Built

Contract

Invariants

  • INVARIANT: All map mutations flow through POST /api/projects/[id]/actions; no direct DB writes from UI
  • INVARIANT: Planning LLM never generates production code or triggers builds
  • INVARIANT: Build agents write to feature branches only; PR merge is user-gated
  • INVARIANT: Every action batch validates schema, referential integrity, and policy before apply
  • INVARIANT: Card finalization must precede build dispatch

Boundaries

  • ALLOWED: Planning LLM creates workflows, activities, cards; proposes planned files; links context artifacts
  • FORBIDDEN: Planning LLM writes to GitHub, creates real files, triggers code execution
  • FORBIDDEN: Build agents merge to main, skip checks, or auto-approve PRs

Overview

Single-user desktop app. Next.js serves UI + API. Electron wraps it. SQLite stores all state locally. RuVector stores embeddings locally. Anthropic API provides LLM. Build agents run in-process via @anthropic-ai/claude-agent-sdk.

┌─────────────────────────────────────────────────────────────┐
│  Electron Shell                                              │
│  ┌──────────────────────────────────────────────────────┐   │
│  │  Next.js 15 (standalone)                              │   │
│  │  ┌──────────┐  ┌──────────┐  ┌───────────────────┐   │   │
│  │  │ React 19 │  │ API      │  │ Claude Agent SDK  │   │   │
│  │  │ UI       │──│ Routes   │──│ (in-process,      │   │   │
│  │  │          │  │ /api/*   │  │  streaming query)  │   │   │
│  │  └──────────┘  └────┬─────┘  └─────────┬─────────┘   │   │
│  │                     │                   │             │   │
│  │  ┌──────────────────┴───────┐   ┌──────┴──────┐      │   │
│  │  │ SQLite (better-sqlite3)  │   │ RuVector    │      │   │
│  │  │ ~/.dossier/dossier.db    │   │ (WASM,      │      │   │
│  │  │                          │   │  384-dim)   │      │   │
│  │  └──────────────────────────┘   └─────────────┘      │   │
│  └──────────────────────────────────────────────────────┘   │
│            │                                                 │
│  ┌─────────┴──────────┐                                     │
│  │ Local Git Repos    │──── push ────▶ GitHub                │
│  │ ~/.dossier/repos/  │                                      │
│  └────────────────────┘                                      │
└─────────────────────────────────────────────────────────────┘
           │
           ▼
     Anthropic API
Layer Technology Location
Desktop shell Electron + Forge electron/
UI React 19 + Tailwind v4 + shadcn/ui app/, components/
API Next.js App Router (route handlers) app/api/
Database SQLite via better-sqlite3 (local, no Supabase) lib/db/
Planning LLM Anthropic Claude (streaming + non-streaming) lib/llm/
Build agents @anthropic-ai/claude-agent-sdk query() (streaming, in-process) lib/orchestration/
Agent definitions agentic-flow registry (system prompts only) node_modules/agentic-flow/
Embeddings all-MiniLM-L6-v2 (ONNX WASM, local) lib/memory/embedding.ts
Vector store ruvector-core (native, local) lib/ruvector/
Memory SQLite content + RuVector vectors lib/memory/
Schemas Zod (slice-a, slice-b, slice-c) lib/schemas/

Data Model

Project 1──* Workflow 1──* WorkflowActivity 1──* Card
Card 1──* CardRequirement, CardKnownFact, CardAssumption, CardQuestion, CardPlannedFile
Card *──* ContextArtifact  (via card_context_artifact)
Project 1──* ContextArtifact, PlanningAction, SystemPolicyProfile (0..1)

OrchestrationRun *──1 Project
OrchestrationRun 1──* CardAssignment 1──* AgentExecution, AgentCommit
OrchestrationRun 1──* RunCheck, ApprovalRequest, PullRequestCandidate (0..1)
Project 1──* EventLog

MemoryUnit *──* Entity (via memory_unit_relation)

Full schema details: data-contracts-reference.md


Data Flow (Summaries)

Planning

User chat → Anthropic streaming API → stream-action-parser → PlanningAction[] → validate → apply → SQLite

Detail: planning-reference.md

Map

GET /map → fetchMapSnapshot → PlanningState → buildMapTree → nested JSON for UI

Detail: map-reference.md

Mutation

PlanningAction[] → schema + semantic + guardrail validation → per-action DB writes in transaction

Detail: mutation-reference.md

Build

User trigger → git clone → createRun → per card: feature branch → dispatch → Claude Agent SDK query() (streaming) → agent writes + commits → auto-commit → checks → approval → PR

Detail: orchestration-reference.md

Memory

Card finalize → embed (all-MiniLM-L6-v2) → RuVector insert + SQLite row → Build dispatch retrieves card-scoped then project-scoped

Detail: memory-reference.md


LLM Connection Models

Two distinct connection patterns exist.

Concern Planning LLM Build Agent
Auth ANTHROPIC_API_KEY ANTHROPIC_API_KEY
SDK @anthropic-ai/sdk (Messages API) @anthropic-ai/claude-agent-sdk
Call style messages.create / messages.stream query() — async iterator
Streaming Optional (non-streaming for simple calls, streaming for chat) Always streaming (for await over messages)
Tools None (text output only) Read, Write, Edit, Bash, Glob, Grep, WebFetch, WebSearch
CWD N/A worktree_path (repo clone)
Lifecycle Request-response per chat turn Fire-and-forget; result via in-process webhook callback
Model claude-haiku-4-5-20251001 (configurable) claude-sonnet-4-5-20250929 (configurable)

Key Directories

Path Purpose
app/ Next.js pages + API route handlers
components/dossier/ Domain UI (story map, cards, chat, sidebar)
components/ui/ shadcn/ui primitives
lib/actions/ validate, apply, preview actions
lib/db/ DbAdapter, SQLite adapter, migrations
lib/llm/ Planning prompts, stream parser, skills
lib/orchestration/ Build runs, assignments, dispatch, checks, approvals, PRs
lib/memory/ Ingestion, retrieval, embedding, harvest
lib/ruvector/ RuVector client (vector DB)
lib/schemas/ Zod schemas (slice-a/b/c, action-payloads)
lib/hooks/ React hooks (project, map, actions, build, knowledge)
electron/ Electron main, preload, runtime, window lifecycle

Data Directory (~/.dossier/)

Path Content
config Key=value config (API keys, overrides)
dossier.db SQLite database (all state)
repos/<projectId>/ Git clones for build
logs/ Electron main process logs

Domain References

Domain Doc
Data contracts data-contracts-reference.md
Planning planning-reference.md
Mutation mutation-reference.md
Map map-reference.md
Orchestration orchestration-reference.md
Memory memory-reference.md
API endpoints api-reference.md

Verification

  • DbAdapter is single seam for all persistence
  • All map mutations go through actions pipeline
  • Planning vs Build boundaries enforced in prompts and validation
  • No Supabase, Postgres, or external DB references in source code
  • Build agents use streaming SDK query(), not HTTP webhook from external service