System Architecture

Praxis Prima Est — the seeing makes the doing.

A single-user personal signal-and-report system, controlled entirely from Discord, on a VM with no inbound ports. External and local data normalize into one signal hub, get LLM-scored for relevance, and become three kinds of report: a daily Discord digest, evolving web pages on Cloudflare, and ad-hoc queries. Small decoupled tools do the work; a thin bridge is the reliable core. Tools join as data, not code, and the autonomous parts can never edit the reliable parts unsupervised.

Constraints that shaped everything

Components

bridgeThe reliable core: Discord gateway, job runner (!job/!code), scheduler, the integration registry. Never edited by the bot.
signalstoreThe hub: normalized SQLite signals, dedupe, dynamic feeds, LLM relevance scoring.
local-reportLLM-authored web pages from the hub + rich extras, published to Cloudflare.
local-*Domain tools (weather, netscan, uptime, jot, scout, fitness) — stateful capabilities with JSON CLIs.
_libThe one shared library (headless-Claude wrapper) — the deliberate exception to decoupling.

The whole coupling between core and tools is one file: the REGISTRY. Promoting a tool is adding one data entry.

Data flow

DATA IN ───────────► THE HUB ───────────► DATA OUT 1 external pull signalstore !page → Cloudflare rss → cloud-native ┌──────────────┐ briefing · career-radar github → releases │ normalized │ relocation · fitness │ SQLite │ 2 tool harvest │ + dedupe │ !ingest query uptime · scout ───► │ + LLM score │ ──► notes · weather └──────────────┘ reports.py → Discord digest weather·net·notes·news·uptime 3 direct reads (valid exceptions) fitness suggest · todos · netscan diff ──► pages / digest
The hub-exception rule — index, not cache. The hub stores feed-like signals for cross-source query & scoring. When a consumer needs a tool's rich, computed, or time-windowed view (a netscan diff, a 24h uptime report, a nested fitness suggestion), it reads the tool directly. Flattening rich output into signals loses information — so those views are pulled fresh. That's an intentional seam, not debt.

Trust boundaries

Five gates — hardened at the edge, one powerful interior. The system trusts nothing from outside: messages, feeds, or Claude's own output.

Patterns (the grammar)

registry seam: data not code decoupled CLIs deterministic core, LLM at edges propose-don't-self-edit snapshot vs event outbound-only three report surfaces, one spine