Skip to content

Architecture Decision Records

This index documents all architectural decisions made during Synapse development (v0.1–v0.9+).

Each ADR covers design choices, rationale, and implications. Newer decisions can supersede older ones — see the body of each ADR for status (Accepted / Superseded / Deprecated).


Core Patterns & Schema (ADR-0001 through ADR-0011)

# Title Status
0001 Incremental indexing strategy (mtime-then-hash) Accepted
0002 Datastore split: Postgres for metadata/links, Qdrant for vectors Accepted
0003 Thin ingest seam preserves F17 pluggable provider (I6) Accepted
0004 Embedding dimension and embedding endpoint are configuration, never hardcoded Accepted
0005 Soft-delete for pages and startup-seeded vault_state Accepted
0006 POST /ingest/trigger response contract and startup behaviour Accepted
0007 InferenceProvider ABC and capability-aware routing (I6) Accepted
0008 provider_config + ingest_runs schema; secrets via env only (I6, §12) Accepted
0009 Bounded ingest loop: defaults, cost accounting, token-usage normalization (I7) Accepted
0010 MCP server: stdio transport in v0.2; write_page reuses the ingest primitives (I6, I1, I9) Accepted
0011 The ingest contract: Pydantic schemas for Analysis / WikiPage / Message / ProviderCapabilities Accepted

Graph & Rendering (ADR-0012 through ADR-0016)

# Title Status
0012 4-signal graph edge-weight formula (F4) Accepted
0013 Server-side FA2 layout, coordinate persistence, and determinism seed (I2) Accepted
0014 GraphCache debounce, dataVersion trigger, and GET /graph contract (I2) Accepted
0015 No client-side layout: sigma.js viewer contract (I2 / I4 / I3) Accepted
0016 Obsidian-style graph: structural edges, real-connection sizing, type-as-modulator (F4) Accepted

UI & Frontend Shell (ADR-0017 through ADR-0021)

# Title Status
0017 Three-panel shell: layout, resizing, shared selection model (F1) Accepted
0018 NavRail IA, Ingest Activity View, Provider Selector, Settings, i18n (M4 Phase 2) Accepted
0019 Chat: streaming transport, persistence, <think>/LaTeX, and the G3 gate (M4 Phase 3) Accepted
0020 Document Upload + Scheduled Folder Import (M4-EXT) Accepted
0021 Labeled NavRail Standard + Provider Config CRUD Contract (M4-HARD) Accepted

Retrieval, Chat & Content (ADR-0022 through ADR-0027)

# Title Status
0022 F5 4-phase retrieval + [n] citation architecture (M5 Phase 1) Accepted
0024 Deep Research: bounded multi-query SearXNG loop + ingest-seam synthesis (F10) Accepted
0025 HITL Review Queue + Multi-format ingest (F9 + F12) Accepted
0026 Cascade deletion of wiki pages (F13) Accepted
0027 Read-only MCP server introspection endpoint + Settings panel (F1-MCP-UI) Accepted

Note: ADR-0023 was intentionally skipped during sprint v0.5 — the number was reserved but never assigned. No document exists for 0023; this is a historical gap in the numbering sequence, not a missing index entry.


Configuration & Integrations (ADR-0028 through ADR-0043)

# Title Status
0028 Browser API base is relative; proxy target is a server-only env var Accepted
0029 Remote MCP over HTTP: mount mcp.http_app() at /mcp/server, bearer-token auth, read-only by default Accepted
0030 Embeddings on/off toggle with lexical degrade (global env flag, Postgres keyword fallback) Accepted
0031 OpenAI-compatible embeddings adapter (explicit EMBEDDING_FORMAT, optional EMBEDDING_API_KEY) Accepted
0032 Remote MCP runtime toggle: persisted remote_mcp_enabled flag, always-mount + 404-gate, no remount Accepted
0033 UI-settable MCP access token + "allow without token" (loopback/private only); hashed storage in vault_state, public source always requires the token Accepted
0038 F11 Web Clipper: secure clip ingress model Accepted
0040 Web clipper runtime configuration (GET/PUT /clip/config; DB wins over env) Accepted
0041 SearXNG web-search runtime configuration (GET/PUT /web-search/config; DB wins over env) Accepted
0042 CLI provider subscription auth: OAuth token / ambient login, no API key (F17, I6/I7) Accepted
0043 UI-settable CLI subscription OAuth token (DB-stored, injected into the spawned claude CLI, API key scrubbed from the child env) (F17, I6/I7, §12) Accepted

Advanced Features & Workflows (ADR-0034 through ADR-0051)

# Title Status
0034 Review Queue: proposal model with lazy on-demand page creation (F9 redesign) Accepted
0035 Page content read/edit endpoints (GET/PUT /pages/{id}/content) Accepted
0036 Wikilink-enrichment post-pass (substitution-apply, bounded, provider-agnostic) Accepted
0037 K2 Lint-fix loop (bounded, human-gated wiki health check) Accepted
0044 Review Queue: contextual depth, stable idempotency & bulk actions (F9 depth pass) Accepted
0045 ForceAtlas2 graph layout via fa2_modified (F4, I2) Accepted
0046 Live ingest activity queue with cancel / pause / retry (F9-adjacent, watcher, I1/I7) Accepted
0050 Retrieval scope restricted to wiki/ pages only Accepted
0051 Pluggable PDF extractor seam: Marker over HTTP with pypdf fallback Accepted
0058 Lint parity extension: broken-wikilink category, batch actions, review bridge, orphan delete (extends ADR-0037; B1) Accepted
0059 Chat composer parity: attach-image (capability-aware vision), web-search toggle (amends ADR-0050 — additive [W] namespace), frozen retrieval-mode presets, AnyTXT do-not-mirror (B2; I3/I6/I7/I9) Accepted
0060 Graph visual parity: render-only edge culling, hub labels, node density down-scale (F4, I2/I3; GL4 deferred, GL5/GL6 declined) Accepted
0061 MCP tool expansion (graph-neighborhood / list-reviews / read-source read tools; resolve-review / trigger-rescan write tools gated like write_page) + review bulk-resolve/PATCH REST + trigger-disciplined agent skill (extends ADR-0010/0029/0033/0044; B5/D2; I1/I5/I6/I7/I9) Accepted
0062 Cloudflare Access edge authentication + client service tokens (browser OTP cookie; iOS/clipper/frontend CF-Access-Client-Id/Secret; /mcp/server bypass path); interim before user→vault tenancy (v1.3.9; audit C1/C2) Accepted

Distribution & Security (ADR-0039, ADR-0047 through ADR-0057)

# Title Status
0039 Tauri v2 desktop shell: Vite SPA wrapped in Tauri, native window, cross-platform CI (F15, v0.6) Accepted
0047 Desktop runtime server URL + Connect gate (Tauri first-launch backend binding) Accepted
0048 Dark mode, command palette, UI polish, and desktop pack (v0.6 frontend + Tauri) Accepted
0049 Desktop auto-update over GitHub Releases (unified v* tag, minisign-verified) Accepted
0052 Shared Bearer token auth (SYNAPSE_AUTH_TOKEN): env-only credential, FastAPI middleware, CORS-safe 401 (R10-1, v1.0) Accepted
0053 Runtime UI config-override layer (app_config key/value store; env baseline → DB override; GET/PUT/DELETE /config/app) (R11-2, v1.1) Accepted
0054 Domain taxonomy (controlled vocabulary + ingest auto-tag) and dashboard stats API (/stats/overview, /stats/sections, /ops/backfill-domains) (F18, R12-1/R12-2, v1.2) Accepted
0055 Settings IA v2: two-level nav, focused pages, domain-co-located runtime config, S14–S18 loop-bound keys (v1.2) Accepted
0056 Bounded watcher ingest concurrency (INGEST_MAX_CONCURRENCY, default 3) — prevents bulk-drop flood of DB pool / embedding host / RAM (I7, v1.2) Accepted
0057 Responsive strategy for iPhone/iPad: 3 viewport tiers (767/1023), useViewport() hook, PanelDrawer + uiStore, iOS safe-area/100dvh (R13-11, v1.3) Accepted
0063 Ingest-quality parity: long-source chunked analysis + checkpointing, LLM body-merge on re-ingest, wrong-language page drop (orchestrated route; provider-abstracted, bounded) (F3/I6/I7, R1, v1.3.13) Accepted
0064 Missing-page fan-out (F9 review suggestions) Accepted
0065 Marker large-PDF conversion via page-range chunking — split in the service, shared models, dedicated MARKER_MAX_UPLOAD_BYTES, raised timeout (F12/I7/I1, v1.4.1) Accepted
0066 LLM Wiki 1:1 parity program (v1.5) — amends I9 (multi-provider web search opt-in) + Marker/MinerU posture; 6-phase scope Accepted
0067 LLM Wiki 1:1 generation-semantics parity (D1–D6: generation exclusivity, related: frontmatter, corpus synthesize, query normalization, overview meta) Partially superseded (ADR-0073/0074)
0068 Source Watch imports wider file types (v1.5 P3-c) — scheduled scan extracts csv/html/mdx/rtf/odt/ods/odp + per-schedule allowed/excluded/max-size Accepted
0069 MinerU cloud PDF extractor (v1.5 P3-d) — 3rd pdf_extractor value, opt-in/off-default, API key env-only (secret), pypdf fallback Accepted
0070 Multi-provider web search behind a provider seam (v1.5 P3-e) — SearXNG default; Tavily/SerpApi/Firecrawl/Brave/Ollama-Web opt-in/off-default, cloud keys env-only (secret) Accepted
0071 UI-settable web-search cloud provider API keys (v1.5 P3-e follow-up) — Fernet-encrypted at rest in vault_state, masked posture, SYNAPSE_SECRET_KEY required, DB wins over env Accepted
0072 Runtime toggle for remote MCP write tools (Settings UI) Accepted
0073 Source-grounded generation and review lifecycle parity (v1.6.0) Accepted
0074 Idempotent corpus generation and operator-visible diagnostics (v1.6.0) Accepted
0075 Explicit deployment trust mode and authenticated health diagnostics (v1.6.0; amends ADR-0052) Accepted

LLM Wiki behavioral parity (v1.7.0 — ADR-0076 onward)

# Title Status
0076 Block-based ingest pipeline and orchestrator decomposition (v1.7.0) — ports nashsu/llm_wiki markdown-analysis + FILE/REVIEW blocks; fixes the link regression at the prompt; enrich default OFF Accepted
0077 Schema-driven page-type routing and an open page-type set (v1.7.0) — schema.md Page Types table is authoritative; custom types persist as raw page_type on the block path; enum untouched Accepted
0078 Aggregate file ownership: index.md "## Recently Updated" (hybrid K3+§1.8), log.md heading format, overview.md manual-op only — removes per-ingest _update_overview; adds POST /ops/overview/regenerate (v1.7.0) Accepted
0079 WS-C Review parity: drain-sweep, stub-create, block-review enqueue (v1.7.0) — onQueueDrained drain callback replaces per-run sweep; create_page_from_review(mode="stub") default; REVIEW blocks → review_items; _detect_page_type port Accepted
0080 Lint parity assessment (v1.7.0) — already at parity (0.74 threshold, deterministic fixes, proposal_origin="lint" review routing); bounded semantic loop vs single-pass and on-demand vs auto-route are deliberate supersets; no code change Accepted
0081 New-vault onboarding wizard, scenario templates, and per-vault output language (v1.7.0; migration 0032; amends ADR-0082) — templates carry extra_dirs + custom types; scaffold applies scenario; wizard auto-activates Accepted
0082 Multi-vault: Project Launcher & runtime active-vault switch (v1.5 P2) — registry, single-active model, no schema change; renumbered from 0067 in 1.9.0 (duplicate-number collision) Accepted
0083 Parity E2E harness and tolerance bands (v1.7.0) — deterministic 3-doc corpus; file comparator reusing parity_report.analyse() with a wikilink-density metric + 1.5.6 regression sentinel; manual llm_wiki gold + runbook Accepted
0084 Single-shot complete() transport for one-shot LLM seams and 120 s cold-start timeouts (v1.7.0) — replaces chat() with complete() for overview regen + review sweep judge + propose-reviews; raises sweep/propose/overview timeouts 30→120 s; I6-preserving; amends ADR-0078 + ADR-0079 Accepted
0085 Ingest non-convergence diagnostics + on-demand live-smoke lane (v1.9.1 W5, NC-1) — ingest_runs.diagnostics (migration 0035) persists stop_reason/last_errors/tokens; UI surfaces "why it didn't converge"; live pytest marker excluded by default (addopts), run via new workflow_dispatch-only live-smoke.yml; retry-with-injected-context deferred (no seam exists yet) Accepted
0086 Stable JSON error envelope across backend, frontend, and MCP (2.0.0 breaking change 3) — every error body becomes {"error": {code, message, status, details}}; code derived mechanically from SynapseError subclass name (strip Error, snake_case); three handlers (SynapseError / RequestValidationError / HTTPException fallback) all emit the one envelope; 422s carry field-level details; providerClient.formatDetail removed; MCP tool errors intentionally unchanged; retires the 1.9.2 byte-for-bit non-regression contract Accepted
0087 Content Security Policy (SEC-CSP-1 / 2.0.0) — script-src 'self' + style-src 'self' 'unsafe-inline'; unsafe-inline for styles required by KaTeX HTML+MathML output (inline span style attrs), React inline style={{}} props (1 765 occurrences), and index.html inline <style> block; dev/CI Vite headers broaden connect-src for cross-origin localhost; Playwright E2E suite in e2e/csp.spec.ts verifies zero violations in both themes across Chat/Search/Graph/Settings/KaTeX Accepted

iOS redesign (Track iOS 2.1 — ADR-0088 onward)

# Title Status
0088 iOS app redesign foundation (Track iOS 2.1, Fase A) — native SwiftUI confirmed over Tauri/web-wrapper; brand-aligned DesignSystem/ (SynColor/SynFont/SynSpace ported from desktop theme.css, accent #2563eb, never pure black) supersedes the legacy Apple-indigo/#000 Theme.swift; native 5-tab shell (Home·Wiki·Chat·Graph·More); documented graph-render spike (WKWebView sigma embed vs native Canvas/SpriteKit/Metal, both I2-safe) — native recommended but Proposed pending on-device perf sign-off Accepted (foundation); graph-render Proposed
0089 overview.md regen bumps data_version (post-2.1.1) — amends ADR-0078's queue-drain refinement: _write_and_index_overview now calls bump_version() on a successful overwrite so the SSE /events channel notifies live clients; degrade/timeout/empty-narrative paths are unaffected (no spurious bump); O(1) atomic UPDATE, no extra provider call (I1/I7) Accepted
0090 MCP OAuth 2.1 + PKCE authorization server for claude.ai custom connectors — amends ADR-0029 §2.2's OAuth deferral: /authorize·/token·/register·.well-known/* (root-level paths, matching claude.ai's observed fallback) gate an OAuth-issued access token behind the SAME static MCP token approving the consent step; JIT client registration + PKCE-only public clients; rotate-on-use refresh; shares the remote_mcp_enabled floor with /mcp/server Accepted