The honest map of the machinery: what each part is, which repo it lives in, and how a labeled issue becomes a running app. Read this first hour here, then go deeper in Platform Internals and Security Model.
The one diagram
flowchart LR
subgraph forgejo["Forgejo — git.espoautos.com (control plane)"]
I[Issues / PRs]
P[Packages: OCI images + charts]
A[Actions CI]
end
D["Dispatcher (plat/agents)\nwebhooks + 60s sweep"]
M["MCP (plat/mcp)\nmcp.espoautos.com"]
G["plat/gitops repo"]
F[Flux]
subgraph cluster["Cluster"]
PL[Platform components]
APPS["Apps: one namespace per env"]
end
CI["Isolated CI pool\nruns-on: isolated"]
R["Node registry mirror\n127.0.0.1:31100"]
GR["Grafana + Prometheus\ngrafana.espoautos.com"]
I -- "webhook: POST /hook" --> D
D -- "spawns agent runs,\nposts PRs/comments" --> I
D -- "tool calls" --> M
M -- "commits overlays" --> G
G -- "converges (1m)" --> F
F --> PL
F --> APPS
A --> CI
CI -- "buildctl push image + chart" --> P
P -- "OCIRepository pull" --> F
R --> cluster
D -- "/metrics" --> GR
M -- "/metrics" --> GR
GR -- "/flow-api overrides" --> D
Control plane: Forgejo
Forgejo at https://git.espoautos.com is not a component of the platform — it is the platform's interface. Repos, issues, PRs, labels, milestones, Actions runs, and the package registry are the entire state surface: every state change is a git commit or a Forgejo API event, so everything is auditable, diffable, and webhook-observable. Apps are generated from plat/_app-template; every app's container image and Helm chart live in Forgejo's own OCI package registry under the owning org.
The plat user is the platform admin: site admin of Forgejo, owner of the system repos (plat/gitops, plat/mcp, plat/agents, plat/_app-template, plat/ci-runner). Its admin PAT powers the dispatcher and MCP internally but never reaches an agent run — runs get per-repo deploy keys and scoped tokens instead, and tenant CI gets a per-org write:package-only REGISTRY_TOKEN, never the admin PAT.
Brain: the dispatcher (plat/agents)
A single daemon that turns Forgejo into an autonomous software factory. It listens for Forgejo webhooks on POST /hook and runs a full reconciliation sweep every 60 seconds — webhooks are fast but lossy; the sweep is slow but complete. On each of its triggers it spawns a Claude Code subprocess in one of five roles: creating a repo fires the builder (v1 from a repo description — one per repo, ever), labeling an issue agent-work queues the worker (issue → PR; the label IS the queue), applying plan-org to an org's _plan seed issue launches the planner (org → app suite + roadmap), a repo arriving via Forgejo "New Migration" dispatches the migrator (imported repo → platform integration), and a PR dropping its 🏗️ title prefix summons the reviewer (adversarial browser validation) — each with per-run scoped credentials and metered cost.
The dispatcher is also the money system: a rolling-window USD spend ledger consulted at enqueue, with per-org ceilings and breakers plus a fleet-wide governor pacing everything to one Anthropic subscription. Operators steer it live — see Steering the Fleet.
Hands: MCP (plat/mcp)
The platform's API for agents and humans alike, at https://mcp.espoautos.com/mcp (Streamable HTTP, OAuth 2.1 or a Forgejo PAT). It wraps Forgejo (git, PRs, issues, CI), Kubernetes (status, logs, query_db), and the app lifecycle (create_app → release_app → delete_app) so that building and operating an app is entirely tool calls — no direct kubectl, no hand-written YAML. Agent runs get run-scoped tokens pinned to one repo or org with a deliberately narrow tool allowlist; it also serves the /ci/preview and /ci/sync-env endpoints that app CI calls to provision preview environments and sync secrets. Full tour: Connect Your Agent.
Substrate: gitops + Flux
Everything the platform runs — Forgejo itself, the dispatcher, MCP, monitoring, and every tenant app — is a file in plat/gitops. Flux sources that one repo and converges the cluster to it on a 1-minute interval. Platform components live under clusters/local/platform/; each app gets an overlay under clusters/local/apps/<org>/<app>/<env>/ containing its namespace, optional Postgres (CNPG), TLS certificate, ingress, and sops-sealed secrets. The overlay is the source of truth: adding one deploys the app, deleting it (with prune) removes everything — deleting only the namespace doesn't work, Flux resurrects it. Every secret in the repo is SOPS-sealed to a single sovereign age key. Details: Platform Internals.
Muscles: the isolated CI pool
All CI runs on a non-privileged pool: a workflow declares runs-on: isolated and gets an ephemeral, KEDA scale-from-zero runner (the plat/ci-runner toolchain image) with a rootless buildkit sidecar and a smoke Postgres — no Docker daemon, no ServiceAccount token, no metadata endpoint, egress-scoped by NetworkPolicy. Builds go buildctl → push image + chart to Forgejo packages → cosign sign; Flux's OCIRepositories pull the chart back out. Node-level pulls of platform images go through a per-node loopback registry mirror at 127.0.0.1:31100, frozen into containerd config at cluster creation. More: CI and Builds.
Ledger: Grafana + Prometheus
Prometheus (60-day retention) scrapes the dispatcher's and MCP's /metrics; Grafana at https://grafana.espoautos.com (sign in with your Forgejo account) renders the fleet dashboards — allocation and burn, flow dams, dispatcher health, runs and repos. It is a control surface too: the Business Forms panels POST flow overrides through a session-gated /flow-api route back to the dispatcher, so being signed into Grafana is the credential. On a freshly-germinated lean daughter the monitoring stack — Grafana included — is stripped, so that form-panel route exists only on the parent/full profile; the fleet-status issue and the dispatcher's own operator flow API (port 9909, e.g. via the plat-flow CLI) still work everywhere.
One loop, end to end
Label an issue agent-work → the webhook wakes the dispatcher → it spawns a worker with scoped credentials → the worker pushes commits to an agent/issue-N branch and opens a PR → the check workflow runs on the isolated pool → CI POSTs /ci/preview to MCP, which commits a preview overlay to gitops → Flux deploys a real preview environment → the reviewer browser-tests it and posts a verdict → auto-merge → auto-release builds and pins a new prod chart version → Flux rolls prod, and Grafana metered every dollar of it. Every arrow in that sentence is a git commit, a webhook, or a tool call — nothing moves outside the control plane.
For everyone
Experience
Operate
Under the hood
Grow
This wiki ships inside plat/mitosis (wiki/) — edit it there, not here. Grown by the platform it describes.