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
Outbound-only. No inbound ports — every external touch dials out
(Discord, Cloudflare, collectors). There is no server to attack.
Single operator. One authorized Discord identity; everything
downstream assumes that check passed.
Decoupled tools. Each local-* is self-contained and
talks to others only through its CLI (run.sh … --format json).
Components
bridge
The reliable core: Discord gateway, job runner (!job/!code), scheduler, the integration registry. Never edited by the bot.
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.
A — Auth. Only the one authorized user; all else ignored.
B — Command surface.!run/!job: whitelist, first token only (no arg-smuggling). !cat: jailed, secrets denied. !code: any project except the bridge itself.
C — Core vs. tools.!reload validates a registry edit before importing — a broken edit is refused, not loaded.
D — Propose, don't self-edit. Autonomous output is quarantined until you apply it: !code→branch, bridge_sync→paste, curator→reversible overlay, LLM HTML→behind Access & static-only.
E — Secrets (softest).!code/!page jobs inherit the host env (tokens, filesystem). Contained only by A + B + D — the real attack surface, named not hidden.
Patterns (the grammar)
registry seam: data not codedecoupled CLIsdeterministic core, LLM at edgespropose-don't-self-editsnapshot vs eventoutbound-onlythree report surfaces, one spine