Table of Contents
- Grow one locally
- The YOUR PLATFORM card
- What germination actually does
- Seed children of your own
- Real domain, bare VPS
- Add a node
- Why you can trust the seed
- Lineage
- Genealogy is triple-recorded and human-readable. The ORIGIN file appends one line per germination — <domain> germinated-from <parent> <date> seed=<file> — the seed manifest records a durable createdFrom URL, and your Forgejo permanently records the migration source on the forked plat/mitosis repo itself. The flagship instance, open-platform.sh, is the root of the tree; every daughter can trace its way back — and every daughter can seed daughters of its own.
This platform can reproduce. In under an hour you can grow a complete, sovereign copy — your own Git server, CI, registry, and AI build crew — on a laptop, a bare VPS, or a fleet. Nothing is shared with the parent: not keys, not secrets, not credentials.
Grow one locally
You need Nix (with flakes), Docker (~4 CPUs / 8 GB), host ports 80/443 free (or set HTTP_PORT/HTTPS_PORT), and one Claude credential — CLAUDE_CODE_OAUTH_TOKEN (subscription) or ANTHROPIC_API_KEY (API billing). The credential is optional, but without it the agents sit idle. Linux is the tested path; macOS works on a best-effort basis.
git clone https://git.espoautos.com/plat/mitosis
cd mitosis
CLAUDE_CODE_OAUTH_TOKEN=<token> nix run .#up
That's the whole install. First run takes 30-60 minutes and completes unattended: cluster creation (~2 min), Git server bootstrap (~2 min), GitOps reconcile + Postgres cold start (10-20 min), then your cluster builds its own platform images through its own CI (15-25 min). If anything fails: k3d cluster delete plat and re-run — setup is one-shot by design, with no half-finished states to untangle.
The YOUR PLATFORM card
Germination ends with a boxed card containing every sovereign value. It is printed once and never written to a file. On it:
- Your domain and the Forgejo admin login:
platplus a freshly minted 32-hex password. - The sovereign key path — the age key that seals every secret on your platform, with its warning: keep this file safe, forever. Germination will not even start until you've backed it up and explicitly acknowledged custody (
FORK_KEY_BACKUP=<path>, then typeYES— orFORK_KEY_ACK=1for non-interactive runs). - Reach-it instructions: the
/etc/hostsline, the per-OS CA trust command, and a port-forward fallback. - The build-your-first-app recipe and the pointer for seeding children.
If you germinated without a Claude credential, the card includes the exact sops set + flux reconcile recipe to seal one in later. From here, follow Build Your First App on your own instance.
What germination actually does
The daughter shares nothing with its parent:
- Mints a fresh age key — the parent's key is never needed and never present; the seed's sealed values are inert ciphertext without it.
- Regenerates every platform secret sealed to your key: admin password, tokens, OAuth app, webhook HMACs, registry credentials, QA user.
- Restores the system repos from seed bundles and re-pushes them to your Forgejo — gitops, mcp, agents,
_app-template, ci-builder, ci-runner, mitosis, hello — with workflow-file branch protection applied to every one. - Builds its own images and charts through its own CI, then verifies each tag is actually served by your registry before declaring success — a germinate that prints "success" with a missing chart is impossible.
- Rewrites identity to your domain everywhere: in-cluster DNS, app URLs, OAuth redirects — and this wiki ships in the seed, so your daughter is born with its own copy, links pointing at its own domain.
Seed children of your own
From a checkout against your running platform:
PLAT_PAT=<a Forgejo PAT with repo read> nix run .#seed
This writes seed-<timestamp>-lean.tar.gz and prints its manifest. The seed is git bundles plus a manifest — it carries no age key, so it leaks nothing usable. Hand the seed and this repo to anyone; they run nix run .#up and get a platform with a brand-new encryption key and freshly minted secrets, sharing nothing with yours. PROFILE=full additionally bundles your app repos.
Real domain, bare VPS
One >=8 GB VPS (Ubuntu 24.04) reached through a Cloudflare Tunnel — no inbound ports, no load balancer. The shape:
-
Create the server with cloud-init that writes
/etc/rancher/k3s/registries.yaml(pointinggit.<domain>athttp://127.0.0.1:31100) before installing k3s with--disable=traefik --disable=servicelb— k3s wires the registry mirror only at install time. -
Create a Cloudflare Tunnel with public hostname
*.<domain>→ servicehttp://traefik.kube-system.svc:80. -
Import the ci-runner image once from any Docker machine — a bare k3s box has no Docker, so germinate can't bootstrap the CI toolchain itself:
tar -xzf genesis/seed.tar.gz -C /tmp/mitosis-seed git clone /tmp/mitosis-seed/repos/plat__ci-runner.bundle /tmp/ci-runner docker build -t git.<DOMAIN>/plat/ci-runner:0.1.0 /tmp/ci-runner docker save git.<DOMAIN>/plat/ci-runner:0.1.0 | ssh root@<server-ip> \ 'ctr --address /run/k3s/containerd/containerd.sock -n k8s.io images import -'Skip this and the platform stands up fine but no CI ever runs.
-
Germinate:
KUBECONFIG=/etc/rancher/k3s/k3s.yaml DOMAIN=<domain> CUTOVER_TUNNEL=1 CLAUDE_CODE_OAUTH_TOKEN=<tok> nix run .#germinate— 15-30 minutes on a cold box.
One honest edge: browser-trusted TLS still depends on a public ACME issuer that hasn't landed yet, so you'll import the platform CA until then. The full runbook, including the cloud-init file and a troubleshooting table, is docs/deploy/hetzner-vps.md.
Add a node
Joining a machine to a running platform is three commands on the new machine and zero commands anywhere else: join the tailnet with routes accepted, write the registry shim, install the k3s agent against the one API endpoint. The routed fabric — subnet-routed container network, one stable API address, a DaemonSet that keeps NIC offload sane — is standing infrastructure that survives reboots; a new node is Ready in about 35 seconds. Runbook: docs/add-a-node.md.
Why you can trust the seed
Reproduction is continuously proven, not assumed. Every PR that touches the seed, the scripts, or the flake — plus a nightly run — germinates a complete platform from scratch on CI and runs the coldstart gate: assertions A1-A7 check that Flux converges, governance policies are live, the webhook is singular and idempotent, the registry mirror serves pulls, and the fork genealogy is recorded. The nightly adds the end-to-end phase E1-E8: a canary app is generated from _app-template and must build, preview, validate, auto-merge, and serve 200 in production with no human involved. The seed you clone passed that gate. (The gate runs on a dedicated host-mode runner; see Reference for the assertion table.)
Lineage
Genealogy is triple-recorded and human-readable. The ORIGIN file appends one line per germination — <domain> germinated-from <parent> <date> seed=<file> — the seed manifest records a durable createdFrom URL, and your Forgejo permanently records the migration source on the forked plat/mitosis repo itself. The flagship instance, open-platform.sh, is the root of the tree; every daughter can trace its way back — and every daughter can seed daughters of its own.
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.