- No secrets on prod beyond: Gitea's own keys, the GitHub OAuth client, the MCP's OAuth client, and the seat keys listed in the ledger. Adding one is a decision.
- Every agent acts as itself (its own Gitea login). No service tokens.
- Port pieces from the old instance only when a card needs them, after reading them, one piece per commit, logged in docs/rebuild.md.
## Ledger
- 2026-10-14 · **Green Tea v1 is a fresh prod, not a migration.** Nothing copied from hb-5 (no issues, labels, secrets, tokens). Why: the old factory was scaffolding; the rebuild is the portability test, and chai gets a box with no dev cruft.
- 2026-10-14 · **GitHub-backed Gitea on Fly.** Gitea stays (ownership, a place for chai to be admin); GitHub is upstream for Time and the first login. Why: Time is GitHub-native and already works; Gitea is cheap to run and keeps the sovereignty option.
- 2026-10-14 · **Logins: GitHub now, nostr next.** Auto-registration from GitHub; no local sign-up. Why: one click for collaborators; nostr gives agents and anyone else a key-based identity (see well-known.online).
- 2026-10-14 · **Tea MCP is off the Mac.** New Green Tea MCP on Fly, OAuth against prod Gitea, every tool as the caller. Why: the MCP is the product surface; it should be reachable without the operator's machine and must never outrun the caller's permissions.
- 2026-10-14 · **Boring stays on the Mac.** It is the operator's admin lane, not a prod component. Why: the thing that can repair prod and the thing that runs prod are different boxes with different owners.
- 2026-10-14 · **Codex is not installed on prod.** Seats are API-driven (Claude API, Venice); Codex on demand as a Fly Sprite. Why: no resident credentials on the runner.
- 2026-10-14 · **Fly cost accepted** for prod (two small apps). Same category as Venice credit.
- 2026-10-14 · **Mac runners reversed.** Last week's move of runners onto hb-5 is undone on purpose (portability exercise).
- 2026-10-14 · **Venture loop on teahubxyz/time paused** until the audit's remaining items are judged safe (3 criticals + 3 highs fixed in time#45, #46).
- 2026-10-14 · **well-known.online is a separate product**, not a Teahub component; may later be prod's signup front door. No dependency either way.
- 2026-10-14 · **The Mac's Gitea stays, as a separate unit.** The operator keeps a Gitea on hb-5 to play with customisation. It is not connected to prod: no mirrors, no shared users, no shared tokens, no DNS under teahub.xyz pointing at it beyond the archive hostname matcha.teahub.xyz (which may go). Why: Teahub and the Mac are distinct units; the Mac's job is maths and experiments, prod's job is being prod.
- 2026-10-14 · **Graduated ventures are orgs on prod** (persimmons, phast, phly …), treated as independent clients of Teahub with their own repos and a pages convention. Not wholesale imports; each starts from what it actually is. Why: a venture with its own domain is a client, not a folder of the factory.
- 2026-10-14 · **notplanned + venture pages merge into Time's venture loop on GitHub**, not into prod Gitea. Why: Time already is the venture loop; two listings would drift.
- 2026-10-14 · **Scouting is plural.** Time's trending-repos scout stays the first source; notplanned's curated backlog is a second source into the same pitch round; more sources can be added the same way. notplanned is not "the" scout. Why: popularity and wanted-but-unbuilt are different signals, and the loop should be able to take several.
- 2026-10-14 · **The old Fly edge is down; its sites are dark on purpose.**`teahub-gitea` scaled to zero (app kept, no machines). Dark until ported: persimmons.app, phast.app, phly.cloud, yolopreneur.lol apex/www, supertestnet.lol, notplanned., maths., 🫖, matcha.teahub.xyz. Per-venture `<slug>.yolopreneur.lol` Workers are unaffected. The Mac is now reachable only over the tailnet; the last public wire into it is cut. Port order: persimmons, phast, yolopreneur apex. Why: the edge was the only thing coupling public DNS to the Mac, and nothing behind it had meaningful traffic.
- 2026-10-14 · **Time moves to prod. GitHub was the proof of concept.** Supersedes the "GitHub is upstream for Time" clause above and the "merge into Time on GitHub" entry: the factory runs on prod Gitea, in one place, with Gitea Actions. `teahubxyz/time` on GitHub becomes read-only once the port lands; no two-way issue sync, ever (Time's state is its issue comments, and a mirrored state machine is a conflict generator). Steps: Fly runner → Gitea backend behind Time's forge module → migrate `time` with issues once → flip workflows to `.gitea/workflows` → archive GitHub copy. Why: Time in one repo host and Teahub in another made no sense; everything on GitHub would defeat standing up Gitea at all.
- 2026-10-14 · **Runner on Fly: `green-tea-runner`** (act_runner 5.0.0-dind, iad, shared-cpu-2x/4GB, 10GB volume holding Docker's data root — Fly's rootfs is overlay so `/var/lib/docker` must live on the volume). Labels `ubuntu-latest`, `ubuntu-22.04` → `node:22-bookworm`. Registered instance-wide as `fly-iad-1`. Smoke: `teahubxyz/teahub``.gitea/workflows/smoke.yml` green. Why: Actions on prod are a precondition for Time on prod.
- 2026-10-14 · **Time landed on prod** (`teahubxyz/time` native, migrated once with issues; port merged as time#47; GitHub copy archived with a pointer). Workflows stay in `.github/` (Gitea reads it). Trust = repo owner, `TIME_TRUSTED` variable, or collaborator, because the Actions token can't read permissions. `venture.py` is not ported yet (time#48); venture loop stays off. Why: see the entry above; one host, no sync.
- 2026-10-14 · **First product secret on prod: `VENICE_API_KEY`** on `teahubxyz/time` (repo Actions secret; the same key the old factory used, taken from its delivery on hb-5, never printed). With it: `TIME_WORKER=venice:qwen coder`, `TIME_REVIEW=venice:grok`, `TIME_MODE=live`, `TIME_AUTOMERGE=on` (merges only on a trusted Approve + green CI, never on protected paths). Why: seats are the product; the operator said the key lives with Boring's deliveries, and the factory is meant to run without hand-offs.
- 2026-10-14 · **Pages convention: `<org>/site` is served at the org's domain by `green-tea-pages`** (Fly, stdlib static host, one shallow clone per site, pull on a Gitea push webhook or every 5 min; code in `pages/`). Supersedes "Cloudflare Pages by default" in #2. No tokens anywhere: site repos are public and cloned over https. Why: the simplest thing that makes "a commit to site ships" true on prod itself, with nothing on the Mac and no new secret.
- 2026-10-14 · **persimmons and phast are ported as orgs, as they were.**`persimmons/app` (+ vendored `human_vault.py`), `persimmons/extension`, `phast/app` (+ `acp/`); `persimmons/site` and `phast/site` live at persimmons.app and phast.app (certs issued, DNS moved off the dead edge). Neither app runs yet: persimmons signs in with Gitea passwords, which prod does not have (needs Gitea OAuth, like the MCP); phast's production blockers (volume, owner auth) stand. persimmons.app says so on a holding page; phast.app serves its landing. Why: the domains were dark; the code is where its owner is; the runtime seams are cards, not blockers for the port.
- 2026-10-14 · **Skills are vendored into the spine at `.agents/skills/`**, not installed per seat. First set: `brag-slim` (latent-spaces/brag) and six of coreyhaines31/marketingskills (`product-marketing`, `launch`, `social`, `content-strategy`, `copywriting`, `marketing-loops`); `evals/` left out. Both MIT. Why: seats on prod are API-driven with no home directory to install into, so the repo checkout is the only place a skill reliably exists; the factory just got dev.to and Bluesky, and `marketing-loops` is the shape Time can schedule. More skills go in the same way, by copying the folder.
- 2026-10-14 · **One venture ledger, at yolopreneur.lol.** Time's ventures and notplanned's are one list (`ventures.json` + `backlog.json` on time's `gh-pages`, with a `source` field); `teahubxyz/notplanned` is on prod with its 4 issues; the index is hand-authored (neo-brutalist) and renders the JSON, so the generator writes data only. Supersedes the "notplanned merges into Time on GitHub" entry. Why: two listings drift, and the operator wanted one.
- 2026-10-14 · **Every venture is static, on Teahub pages, at `<slug>.yolopreneur.lol`. No Cloudflare.**`*.yolopreneur.lol` → `green-tea-pages` (wildcard cert); the apex `/<slug>/` redirects to the subdomain; a venture ships as `ventures/<slug>/` on `gh-pages` and nothing else is provisioned. The nine Workers (`time-<slug>`) and their custom domains were deleted with the Workers token on hb-5; `backend` is gone from `ventures.json`; `time.js` degrades without `/api/`. `cloudflare.py`/`worker.js` leave with the venture.py port (time#48). Kept for now: `time-aicharts` (the lab, no static twin — rebuilds on prod per #5) and `jev-prefab-decider` (not Time's). D1 databases could not be deleted with that token (no D1 scope); the Workers that used them are gone, so they cost nothing but still exist. Why: one format for all sixteen, and no Cloudflare spend.
- 2026-10-14 · **Second product secret on prod: `ANTHROPIC_API_KEY`, user-level on `teahubxyz`** (Actions secret shared by every repo teahubxyz owns; taken from Boring's delivery on hb-5, never printed; the Gitea token used to set it was minted on the Fly box with `write:user` and revoked within minutes). With it: Time gets Claude seats (`haiku`, `sonnet`, `opus`, `fable`) through the Claude API's OpenAI-compatible layer, `TIME_WORKER=claude:sonnet`, and a **spend governor**: a ledger in the repo (`time/ledger/<month>.jsonl`, one line per model call with tokens and USD), `TIME_DAILY_USD=5` and `TIME_MONTHLY_USD=100` as user-level variables; a daily breach opens an `andon` issue and waits for midnight, a monthly breach also flips `TIME_MODE` to `dry-run`. Venice stays wired but is no longer the worker. Why: the operator's Max plan outruns manual use and the factory should run on API credits unattended; Venice burned $20 of $75 before anyone noticed, so the cap is counted in dollars by code, not in launches, and no model decides whether to spend.
- 2026-10-14 · **Time is a Gitea user: `time`, with its own token.** Gitea 1.24 lets the Actions identity (`gitea-actions`) comment and label, and git-push with the task token, but never open or merge a pull request ("user must be a collaborator") or write through the contents/branches API (pre-receive denies it). So Time's writes go over `git push`, and the two PR calls (open, merge) go out as `time`: a bot user, collaborator (write) on `teahubxyz/time`, token scoped `write:repository,write:issue`, stored as the repo secret `TIME_TOKEN`, minted on the Fly box, never printed. Operator approved. Reading of the standing rule: Time is an agent and this is Time acting as itself, not a shared service token; nothing else uses `TIME_TOKEN`. Also today: the daily planner `astra.py`/`astra.yml` (one Opus call a day, queues ≤2 cards, writes to the "Astra log" issue; off until `TIME_ASTRA=on`), and the first Claude-seat card, time#49, is the one that found all three Gitea walls. Why: without an identity that can hold a PR the council has nothing to review and nothing ever lands.