architecture

Updated · View the entry on sijie.xyz ↗

Source of truth (July 2026)

The CODE is the only source of truth for what exists; THIS wiki is the living documentation. The repo's docs/ are input material of decaying authority — usable as leads, never as status:

  • Root README.md: rewritten for the shipped state on 2026-09-05 (00c22ab3b) — now the image-deploy guide; still a seed, not status.
  • docs/design/* + docs/roadmap.md: historical design record + execution tracker — built/unbuilt claims have already drifted (an "OAuth flow not designed" note survived the OAuth landing). Verify every claim against code.
  • docs/protocols.md + docs/theory-foundations.md: dead files — ignore them.

Stack (verified)

  • Go 1.26.3, chi/v5 + sqlc (single backend/db/schema.sql)
  • Postgres/pgvector + Redis + Silo (S3 object store; the MinIO fork)
  • AI core = CloudWego eino v0.9.2 (eino/adk loop; Anthropic → native Messages API adapter, every other provider → OpenAI-compatible adapter)
  • Next.js thin SSE consumer (agent loop runs entirely backend-side)
  • SDK = 5 npm packages: @standmeet/{sdk-core, agent-core, sdk, embed, mcp-client} (sdk/packages/{core, agent-core, react, embed, mcp-client}/package.json — there is no @standmeet/react; the React package is published as @standmeet/sdk)
  • Note: the empty leftover backend/internal/mcp/ dir is gone at 36789537d

The seven pillars

Each pillar is a node under key-designs, carrying its components, code paths, status, and design pages:

  1. corpus — the asset. One corpus_notes table with a genre column (vault-isomorphic raw→wiki→output), derived-path tree, note_refs backlink edge table; all three faces (feed / crawl / render) landed — vault SyncVault routes top-level folders to genres (backend/internal/corpus/obsidian/sync.go), corpus_links walks note_refs (mcp-servers/retrieval/main.go:42).
  2. capabilities — the agent's hands (capability plane). We are MCP host: capreg, five externalized servers, ext-mcp, skills, ui:// cards. The in-process remainder is the externalization migration's target. (The opposite plane — us as MCP server — is service-handle, kept as a separate node.)
  3. connector — the credentialed edge. Hub + category contracts; openapi/protocol kinds; installable connectors landed (fixme tail cleared - 11 mock-infra TODOs remain); sync-mode landed too — connector.NewSyncConnector + the SyncIngester capability made sync/ingest a first-class connector kind, and /obsidian/import now goes through it (the 1↔3 seam, closed).
  4. monitor — call-time telemetry. The thinnest pillar; the mini-Zabbix system panel shipped 2026-09-04 (a5e1cada9 real system observability; e3af33a1c reads the backend's own cgroup, no docker socket — backend/internal/infra/selfstat/selfstat.go; 4a082689a live refresh ~1/s on 2026-09-05).
  5. agent-core — the loop. eino + Bridge/Driver (landed), entry-agnostic, eval-as-consumer.
  6. access-control — the valves. Codes, frozen role snapshots, three-layer pure-AND ACL, BYOAI, Ed25519.
  7. structure — the foundation & discipline. Layering, one schema, error envelope, sandboxes, mechanical guardrails + judgment audit.

Plus the outward face, deliberately not filed under any pillar: service-handle — StandMeet as MCP server (/mcp/*, Sigv1), where the owner's AI pushes and other agents read.

Update — everything-is-a-block (eiab), 2026-09-13 → 2026-09-18

Landed after this node's 2026-09-07 stamp, so pillars 2 and 3 above are superseded in mechanism (the intent stands):

  • Pillars 2 + 3 collapsed into ONE block model. The visitor/leaf capabilities (ask_visitor, summarize_conversation, calendar.book, corpus.retrieval, mail.send) and every connector (caldav, smtp, google-calendar, telegram) are now sandboxed JS blocks — backend/blocks/*/manifest.yaml + a JS MCP server, no per-capability Go. The capabilities/cap* vocabulary was renamed to plugin/block* (backend/internal/plugin/{blockstore,blockconfig,blockquota,blockload}); me/seo/codes became domain fp.Op projected via convergence/dispatcher.
  • backend/internal/connector/ is now empty (0 Go files) — the separate connector pillar is gone. So pillar 3's "sync-mode connector landed / /obsidian/import goes through it" is doubly stale: there is no connector module, and vault sync is still a bespoke admin endpoint (backend/internal/routes/admin/obsidian.go), never unified into a connector (roadmap 1e).
  • Still in-core (not yet blocks): jobs/resume/applications (still MustRegister), so MustRegister + the in-process registry survive; the mermaid's mcp-servers/ stdio children and the capreg / Connector Hub boxes describe the pre-eiab shape.

How the pillars connect

The agent core (5) reads the corpus (1) and wields MCP capabilities (2); capability dependencies are supplied by connectors (3); access control (6) valves everything at the session door; the monitor (4) watches call-time; structure (7) carries it all; corpus sync folded into connector sync-mode (1→3) on 2026-07-08 (d51805372, backend/internal/connector/sync.go:61).

flowchart TB
  V["visitor (QR / access code)"] --> APP
  OW["owner (admin)"] --> APP
  EV["eval-harness (EvalDriver)
same repo, separate go.mod"] -. "same launch handle" .-> CORE
  subgraph SM["StandMeet — our box"]
    subgraph FE["app — Next.js (frontend)"]
      APP["thin SSE shell + reader pages"]
    end
    subgraph BE["backend — Go (one process)"]
      RT["routes"] --> AC{"6 · Access control
global ∧ role ∧ ¬code-deny"}
      AC --> CORE["5 · Agent core
eino loop via Bridge/Driver"]
      CORE --> CAP["2 · Capabilities (capreg)"]
      CORE --> CORPUS[("1 · Corpus
corpus_notes (genre raw → wiki → output) + note_refs")]
      CAP --> CONN["3 · Connector Hub"]
      OBS["4 · Monitor (call-time)"] -. watches .-> CORE
      ST["7 · Structure: chi · sqlc · pg · redis · minio · sandbox · apierr"] ~~~ CORPUS
    end
    subgraph PROC["stdio child processes (own go.mods, sandboxed)"]
      MS["mcp-servers/
ask-visitor · booker · mail-sender · retrieval · summarize"]
    end
    APP --> RT
    CAP --> MS
  end
  CONN --> EXT["external world
GCal · SMTP · CalDAV · Telegram …"]
  OW -- "writes / promotes" --> CORPUS

Roadmap (big blocks, July 2026 — status as of 2026-09-07)

  • The corpus-as-vault block (= pillar 1): landed — all three faces built; the crawl face is Meilisearch as lexical entry + corpus_links (1-hop over note_refs, agent drives depth), deliberately NO vector (see corpus-retrieval).
  • The platform block (= pillars 2 + 5): the externalization migration (in-process registry → independent MCP servers; the feature floor must not shrink) and promoting inject-and-launch to a first-class runtime.
  • Pillar 4 = the system panel — shipped 2026-09-04 (a5e1cada9, e3af33a1c; monitor).
  • The one-command-deploy plan (auto-LE) — CUT July 2026 — owner binds domain/cert at their provider. What did ship instead (2026-09-04, 7a3a749e7 / 3c9fb6113 / 3d1ce1aaf): a product-owned in-place upgrade — an updater sidecar in infra/deploy/docker-compose.yml recreates the stack from a signal file the backend writes (deployment).

Key designs

  • key-designs — the non-obvious, load-bearing decisions
  • confusables — terms that look alike and aren't: the two MCP planes, the two plugin axes, writings vs corpus, frozen vs live, and more

Deployment

  • deployment — self-hosted, single-tenant, single-box; read-heavy / write-light; why "can't scale horizontally" is by design

Related notes