Skip to content

Architecture Decision Records

ADRs document significant architectural decisions and their context.

Agents

ADRDecision
001 - Background AgentsKubernetes-native agent execution with sandbox isolation
002 - OpenHands Agent SandboxOpenHands as the agent runtime framework
003 - Context ForgeIBM Context Forge as the MCP gateway
004 - Autonomous AgentsDesign for fully autonomous agent workflows
005 - Role-Based MCP AccessRole-based access control for MCP tool servers
006 - OIDC Auth MCP GatewayOAuth 2.1 / OIDC authentication for remote MCP access
007 - Agent Run Orchestration ServiceDedicated service for dispatching and tracking agent job runs
008 - Cluster Patrol Loop ResilienceCrash recovery and per-sweep supervision for cluster_agents loops
009 - Automated Test Generation BotsAgent-driven test generation pipeline
010 - Recipe-Driven Agent RegistryGoose recipe YAML as the source of truth for agent definitions
011 - Agent MCP v1 Follow-onsDeferred self-improvement loop scope after v1 MCP surface shipped
011 - Cloudflare Managed OAuthCloudflare-managed OAuth for the MCP gateway (duplicate number)
012 - Knowledge Gardener Model PipelineTwo-tier model pipeline for the knowledge gardener
013 - Knowledge Gardener Gemma4-OnlySingle-model pipeline replacement for the gardener
014 - AX + Substrate Agent RuntimeSplit-roles adoption of google/ax + agent-substrate, retiring orchestrator + cluster_agents
015 - Temporal as Orchestration SubstrateAdopt Temporal for workflow execution + scheduling; supersedes ADR 014
016 - NATS as Canonical Event StreamNATS JetStream as the system-wide event bus between independently-owned components
017 - Domain Event SchemaEvent envelope schema + tombstone semantics across the system
018 - Event-Driven Gardener TriggeringMonolith pushes gardening sessions via remote-trigger run on note edits; drops cron + queue
019 - Substrate Executor + AgentWorkflow over ArgoThin Substrate executor interface (agent-sandbox warm pool impl #1) under Argo; revisits 015's warm-pool dismissal for caller-blocked dispatch
020 - Deprecate Context ForgeRemove the MCP gateway; serve the monolith's MCP directly (auth stays at the Cloudflare edge). Supersedes 003. Validated plan, deferred execution
021 - Discord-Triggered AgentWorkflow with Fast Hosted ModelDiscord bot (qwen gate) as a new AgentWorkflow consumer riding 019's submit path; fast hosted model (Gemini 3.5 Flash) over an OpenAI-compatible seam; snapshot/resume for smooth many-thread work. Draft
022 - Firecracker Snapshot/Restore Controller for AgentWorkflowBuild a thin k8s controller (no turnkey OSS exists); FC-direct, porting E2B's architecture; controller owns idle-detect/snapshot/GC/restore-routing/affinity/reconnect, delegates snapshot to Firecracker. Feasibility derisked (28ms restore)
023 - Egress Secret Proxy for Agent SandboxesGuest holds only placeholders; real secrets swapped in at the vsock 1025 egress hop (not eBPF: microVM has its own kernel, Go has no OpenSSL). Per-secret allowlist is the exfil control. v1 = TLS-terminating sidecar in the fc-agentd DaemonSet; CRD/operator deferred. Draft
024 - Discord Agent, Hosted-Model Tiers, and Isolated Live ArtifactsProductive Discord loop on the 022/023 substrate: hosted model via OpenRouter (per-thread knob, key swapped via 023) to beat the 32k Qwen ceiling; two tiers (coding with a gh token vs zero-secret artifact); agent publishes HTML to S3 served in a sandboxed-iframe opaque origin on jomcgi.dev (no subdomain) with ETag hot-reload. Supersedes 021's Argo framing. Draft
025 - Three-Layer Agent Stack (firecracker-substrate, goosecracker, discord-agent)Name and separate the agent stack into projects/agents/{firecracker-substrate,goosecracker,discord}: firecracker-substrate (bare microVM primitives, goose-agnostic, opaque Exec per 019), goosecracker (generic agent manager owning goose recipes + AgentThread snapshot/resume + a generic config surface; depends on the substrate), and discord (the Discord agent's workload image/source only). goosecracker stays consumer-agnostic; the Discord agent deploys as a generic goosecracker values config and its runtime glue stays in the monolith bot. Re-bins 022/024 components and re-homes 024 Task 1 tier env into the manager layer; no mechanism change. Draft
026 - Hot Git Mirror for goosecracker Agent WorkspacesHot in-cluster git mirror on node-4 feeding goosecracker agent workspaces: warm base stays repo-agnostic, guests partial-fetch a local always-fresh mirror instead of cold-cloning GitHub on every spin-up; a goosecracker-layer concern per ADR 025, keeping GitHub off the spin-up hot path with no token needed to clone. Draft
027 - Agent GitHub App Roles: Implementer and ReviewerSplit the agent's single gh identity into two GitHub Apps mapped to roles: a claude/*-scoped, no-merge implementer (lower-trust model) and an approve-and-merge reviewer (Opus or better, adversarial spec-vs-impl). Merge gated by a reviewer-controlled agent-review/gate status check since App bots cannot be CODEOWNERS; @jomcgi stays the human owner. Role token injected per-thread via the 023 egress swap. Draft
028 - Elastic Agent-MicroVM Capacity and State-Preserving ReclaimRun the disposable agent-microVM tier elastically on a shared node: reaffirm FC-direct (sub-100ms golden-template restore; kata-fc has no CRI snapshot); honest burst via dynamically-sized Guaranteed in-place pod resize + a headroom watermark controller (k8s off the hot path, Infeasible resize = spill signal); critical-tenant-safe reclaim via an idle-first victim ladder + graceful drain (checkpoint -> park -> rehydrate) driven by a free-allocatable cushion + node-pinned-Pending watch; and a filesystem-as-durability-contract state model (/repos git branches to a state remote, /data to S3, rest recomputed) checkpointed as a consistent tuple. Drops per-thread VM snapshots; ballast pods + sharding considered and deferred. Draft
030 - fc-invoke, a Single Configurable Surface for Running Workloads in FirecrackerOne host daemon that implements ADR 019's stubbed Substrate.Exec seam plus the orchestration around it, absorbing semgrep-scand and fc-agentd's VM lifecycle. HTTP ingress -> HTTP-over-vsock reverse proxy into a guest; workloads are named Helm-values entries (seven generic knobs: image/resources/concurrency/egress/warmBase/sessioned/requestTimeout); warm-base (platform VM snapshot) and state hydration (guest-side shim capabilities) split on the litmus line; all durable state owned by orchestrators (stateless daemon, 2-way door); a shared bazel-baked guest shim (HTTP server + git/object-store capabilities) keeps the rich guest toolkit out of the thin host contract. Home projects/firecracker/{substrate,goosecracker,semgrep}. Supersedes ADR 025 in part. Draft
031 - Control-Plane / Data-Plane Split for the Agent Substrate (cluster + node)Split the substrate Go code into a cluster/ control plane (ingress, catalog, future placement + fleet/in-place-resize) and a node/ data plane (invoker, fcvm driver, vsockhttp, egress), bracketed by a neutral substrate.NodeExecutor seam so neither plane imports the other. One binary/Deployment now (in-process local executor); the physical split to a central agent plus per-node DaemonSet later is a wiring change behind the seam, not a rewrite. Accepted

Docs

ADRDecision
001 - Static Docs SiteVitePress for architecture documentation (superseded by 002)
002 - Retire Standalone Web Frontends, Docs into MonolithDelete projects/websites/ + trips/hikes Pages frontends; serve docs from the monolith at jomcgi.dev/docs/*

Networking

ADRDecision
001 - Cloudflare Envoy GatewayCloudflare Tunnel + Envoy Gateway for ingress

Platform

ADRDecision
001 - Obsidian Vault Monolith MigrationMigrate Obsidian vault into the monolith on TigerFS
002 - CDN-Cached Data FetchingPublic JSON endpoints cache at the Cloudflare edge; clients poll cached
003 - CDN Cache Rule Scoped to public.jomcgi.devScope CDN cache rule to public.jomcgi.dev (supersedes 002 partially)
004 - Iceberg-on-SeaweedFS Lakehouse with Hot-Swap Quack ServingEvent-sourced lakehouse; NATS → Iceberg → Quack hot-swap; partially evolves 001
005 - Per-PR Preview EnvironmentsEphemeral monolith previews: CoW Postgres clone, muted side effects, ApplicationSet PR generator
006 - Decommission Obsidian via a Postgres InterimKill Obsidian now: note body authoritative in Postgres, web UI editor; interim ahead of 004
007 - SeaweedFS Bucket Provisioning via COSIDeclarative buckets + lifecycle + per-app creds via COSI; replaces create-only weed-shell Jobs
008 - Monolith Module BoundariesInternal module boundaries within the monolith
009 - Post-Merge Chart Versioning and Kargo PromotionBump versions post-merge on main, not on branches; Kargo dev->prod promotion with synthetic gates
010 - Memory Oversubscription via Burstable QoS + PriorityClassesReserve steady-state via requests and peaks via limits; PriorityClass hierarchy with agent microVMs as designated OOM victims

Security

ADRDecision
001 - Bazel SemgrepSemgrep SAST integrated via Bazel rules
002 - Semgrep Rule Generation via RLRL-finetuned Qwen 3.5 9B for generating Semgrep rules from CVEs
003 - gVisor RuntimeClassUser-space kernel isolation for agent sandbox pods via runsc
004 - Public Read-Only Service IsolationSeparate read-only public service on a replica, isolated from private data and secrets
005 - Public Chat Adversarial HardeningDefense-in-depth for anonymous GPU-backed chat: Turnstile sessions, reserved-headroom semaphore, server-side limits, DB-confined retrieval

Services

ADRDecision
001 - Discord History BackfillOne-time backfill of Discord channel history into pgvector
002 - Discord Chat AutomationScheduling, triggers, and proactive posting for the Discord bot
010 - FastMonolith Modular FrameworkPrivilege-typed, data-isolated domain modules composed into per-tier binaries
011 - Grimoire Hot-Tier SchemaTyped CTI schema + grant-overlay visibility on monolith Postgres, checked out from Loom

Tooling

ADRDecision
001 - OCI Tool DistributionMulti-arch OCI image for developer tools, eliminating local Bazel
002 - Service Deployment ToolingCopier template to scaffold new services, eliminating per-service boilerplate
003 - Spec-First CLI and SkillsOpenAPI as source of truth; CLI commands and Claude skills are derived
004 - OCaml Rules for SemgrepScale the custom bazel/ocaml ruleset (not obazl); ppx first, per-arch native toolchains
005 - tOyCaml DemonstratorEngine-shaped demonstrator exercising the ruleset before Semgrep lands
006 - Multi-arch OCaml ToolchainsData-driven arch registry; per-arch toolchain registration gated on pool verification
007 - OCaml BUILD GenerationGazelle-based BUILD file generation for OCaml sources
008 - CLI Multi-platform DistributionOne Bazel graph, native execution platforms (cloud arm64, self-hosted darwin); no cross-compilation, QEMU, or wasm
009 - Bazel-native Package ClassificationTag/visibility per-package over central globs and gazelle:exclude; lint the old pattern out
010 - Hermetic Visual RegressionMove public-page screenshot capture/diff into cached Bazel actions on an apko chromium image; non-frontend PRs become cache hits