Files
teahub/docs/decisions.md
T

56 lines
34 KiB
Markdown
Raw Normal View History

2026-10-14 05:29:34 +00:00
# Decisions (append-only)
Format: date · decision · why. Add at the bottom. Never edit an old entry; supersede it with a new one.
## Standing rules
- Prod is the cloud instance at teahub.xyz. The Mac (hb-5) is the operator's playground and the archive of the old factory; prod never depends on it.
- 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.
2026-10-14 05:29:34 +00:00
- 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.
- 2026-10-14 · **Correction: the temporary admin tokens were not revoked when this log said.** The `ANTHROPIC_API_KEY` entry says the token used to set the secret was "revoked within minutes"; it wasn't. `gitea admin user` has no command that deletes a token, and the call meant to do it failed without anyone seeing an error. Four short-lived `teahubxyz` tokens (for the user-level secret and variables, Time's repo variables, and the push that made PRs go out as `time`) stayed valid for 11 to 65 minutes, were never printed, and were deleted from the database by 20:23 UTC (`access_token` ids 22, 23, 24, 26). The only token on prod now is `time`'s own (`TIME_TOKEN`). From now on a temporary token is deleted with `sqlite3` on the Fly box, and the deletion is checked by listing the table before anyone writes "revoked". Why: this log is how the next agent knows which credentials exist.
- 2026-10-14 · **Every write Time makes, except comments and commit statuses, goes out as `time`.** Widens the entry above, which covered only opening and merging PRs. Gitea 1.24 also refuses the Actions identity label edits (removing a label is a 500); that crashed `promote_next` after time#50 merged and stalled the queue. `gh()` now sends every non-GET call with `TIME_TOKEN` except comments and statuses, which stay with `gitea-actions` because Time's beats are that author's comments. The `time` user never counts as trusted, mention replies ignore it, and `astra.yml` gets the token too (time `c2055e8`). Three more temporary admin tokens were used this evening, to read job logs and push the fix; each was deleted by id and the table checked (ids 27, 28, 29). Also found: Gitea's label events carry no label name, so labelling a card `ready` doesn't wake the heartbeat; promoted cards wait for the hourly tick. Why: one identity that can actually do the factory's writes, and the Actions identity kept for the two things it reliably does.
- 2026-10-14 · **The factory runs without the operator: Astra is on, and a steward merges engine PRs.** The operator delegated merging and admin to Claude and approved both explicitly. Astra (`astra.yml`, daily at 13:13 UTC, one Opus call) now labels its picks `queued` instead of `ready`, so they line up behind the existing queue and `promote_next` runs one card at a time (time `97b7667`). Engine PRs (anything under `.github/`) still never merge themselves: Time marks them needs-human, and the **Teahub steward**, a scheduled Claude session (cloud, every 6 hours at :47 past 01, 07, 13 and 19 UTC, automatic approval), reads each one, answers the reviewer, and merges it only if CI is green, it does what its card's DONE line says, it touches no workflows, secrets or deploy, and it doesn't weaken the spend governor or the protected-path rule. The steward also works open andons (never by raising a cap or changing `TIME_MODE`) and repairs a failed heartbeat. Its admin tokens follow the rule above: minted on the Fly box, deleted by id, table checked. Tonight time#54 and time#56 were merged that way and `TIME_ASTRA` was set (tokens 30, 31, 34, all deleted); tokens 32 and 33 belonged to another session and were already gone when checked. Why: the operator doesn't want to be the merge gate, and the engine still shouldn't change without someone reading the diff.
- 2026-10-14 · **SKILLS.md is the skills contract**, the third root file beside `AGENTS.md` (how to move here) and `DESIGN.md` (what good looks like): routes (task → one to three skills, named by path), a ledger (upstream ref and tree, version, what each skill writes) and belts (⬜ admitted, 🟩 katas beat no-skill on a named seat, ⬛ grown from our traces, 💤 retired once a seat no longer needs it). Skills are never left to auto-trigger, and no model decides which skill to load. `.agents/skills/README.md` now points to it and AGENTS.md has the move. (The first skills README said Claude Code reads `.agents/skills/`; it reads `.claude/skills/` only.) Why: the Oct 14 skills research — unaided triggering fires about half the time, generic skills often add nothing on strong models, and the trust that holds comes from gates (evals, pinned refs, sandboxes), not prose. Time's seats are plain API calls, so routing has to live in a file every seat can read (#7).
- 2026-10-14 · **phast and persimmons re-ported from their canonical repos; phast runs.** The port above copied `tea-mcp/src` snapshots from Oct 9, older than the canonical `matcha/phast` and `matcha/persims`. So phast.app came up in the old light design and persimmons.app on a holding page. Both canonical repos are now merged, with history, into `phast/app` and `persimmons/app`, and their trees are the canonical ones. **phast**: Fly app `phast-app` (1 machine, volume `phast_data`) serves phast.app, my.phast.app and `*.phast.app` from that one repo: the pages are its `index.html` and `my/index.html`, and the MCP at `my.phast.app/mcp` signs in with Teahub OAuth. The OAuth app is "Phast app", owned by `teahubxyz`, redirect `https://my.phast.app/auth/callback`; the client secret and JWT key exist only as Fly secrets and were never printed. `ALLOWED_GITEA_USERS=matcha,chai`. matcha's Phast app moved from hb-5. Closes phast/app#1. **persimmons**: pages serves persimmons.app from `persimmons/app`'s root (its `pages/page.conf` says `source=.`). The API isn't on prod, so the vault reads "Service unavailable". persimmons/app#1 covers the port, including whether a product backend may hold an admin-scoped token: it creates vault repos and stores PATs as Actions secrets. `phast/site`, `persimmons/site` and `persimmons/extension` are archived with pointers. Pages now serves extensionless HTML (`/signin`) as text/html. Why: the regression was a stale copy, so each product ships from the one repo its owner works in.
- 2026-10-14 · **The portfolio lists the operator's own products too, and phly.cloud is back.** Teahub, Persimmons, Phly, Phast app, MacMCP and Time join the ledger at yolopreneur.lol (25 entries). They are listed like well-known.online: `url` is the product's own address, `ventures/<slug>/index.html` forwards `<slug>.yolopreneur.lol` there, and a first-screen shot (960×600) sits beside it. phly.cloud had been dark since the edge went. Its site, `matcha/phly` with history, is now org `phly`, repo `phly/site`, served by pages (cert issued, DNS moved, push webhook). The favicon pointed at an expired Boring blob link and is now the mascot itself. Still dark and not listed: supertestnet.lol, unicorn.ceo, and the `*.teahub.xyz` sites (maths, notplanned, dreams, oracle, greentea); their bytes are on hb-5 (`~/sites`, the old Gitea). Why: the operator asked for the products in the list; one list, same card for everything.
2026-10-14 15:22:58 -07:00
- 2026-10-14 · **Receipt: temporary admin tokens for the phast/persimmons/phly work.** `teahubxyz` token 35 (`fix-phast-20261014`, minted on the Fly box for the pushes, the OAuth app and the repo archives) was deleted by id at 22:27 UTC, and the table listing shows only 25 (`time`). Token 36 (`receipt-20261014`) was minted only to push this line, then deleted the same way. Neither was printed. Why: the rule above.
- 2026-10-14 · **One tree: lineage is the factory's shape.** The factory, its ventures and their agents are one tree, read three ways at the same path: keys (lineage), context (`AGENTS.md` · `SKILLS.md` · `DESIGN.md`, inherited down the path) and presence (pages; NIP-05/mailr names). Every org runs the same template at every depth, from its own seed (BIP-85 from its parent's root). Edges are *derived* (the parent holds the child's seed) or *adopted* (the child holds its own root and the parent vouches with a birth certificate); graduation flips derived → adopted. Belts are badges, per seat × skill, and `SKILLS.md` now tracks them per seat. Model only: minting a real root is the operator's call. Details and a spec v0.1 proposal in `docs/lineage.md`. Why: the operator saw the meta repo's nesting, lineage's key tree and the yolo portfolio as one shape, liked graduation as an edge flip, and set belts = badges (#8).
- 2026-10-14 · **supertestnet.lol is back, and every Cloudflare domain is in the portfolio.** Cloudflare has one account with 8 zones; Boring's token and the dashboard list the same ones. All are now accounted for: macmcp.xyz, persimmons.app, phast.app, phly.cloud, supertestnet.lol, teahub.xyz and well-known.online are listed, and yolopreneur.lol is the list itself. Super Testnet, a browser-local Bitcoin lab, moved from the old Gitea with its history to org `supertestnet`, with repos `app` and `inscriboor` (the signing extension). Pages serves `supertestnet/app#pages`, which is the build that was live. Pages now reads a `_headers` file (Cloudflare Pages style), so the site keeps the CSP and frame headers its Node server used to send. The ledger has 26 entries, and the hero no longer says every venture came off the clock. unicorn.ceo is not the operator's domain; it was only an idea. Four records still point at the dead edge (66.241.124.48 / 2a09:8280:1::19c:1dd0:0): `matcha.`, `maths.`, `notplanned.` and `🫖.teahub.xyz`. That's harmless while the suspended `teahub-gitea` app holds those IPs and certs, but the records must go before that app is deleted. Of the four, only maths.teahub.xyz (the zeta-ball pictures) has its own content; its files are in hb-5 `~/sites/maths` and `matcha/maths`. Temporary token 37 (`supertestnet-20261014`, `teahubxyz`) did the org, repos, hooks and pushes, and is deleted by id right after this push; the table is checked. Why: the operator asked that every domain be in the list.
2026-10-14 15:41:49 -07:00
- 2026-10-14 · **The four dead teahub.xyz names are gone.** At the operator's word, the records for `matcha.`, `maths.`, `notplanned.` and `🫖.teahub.xyz` (A + AAAA to the dead edge) and the `_acme-challenge` CNAMEs for `maths.` and `notplanned.` were deleted, 10 records in all, through the Cloudflare dashboard session on hb-5. Boring's DNS tool can upsert but not delete. teahub.xyz now holds only the apex (`green-tea`), `mcp.` (`green-tea-mcp`) and the apex ACME CNAME. No other zone points at the old edge, so `teahub-gitea` can be deleted without leaving takeover bait. maths.teahub.xyz's files stay on hb-5 (`~/sites/maths`, `matcha/maths`) for whenever it comes back. Token 38 (`dns-receipt-20261014`) was minted only to push this line and is deleted by id right after; the table is checked. Why: nothing should resolve to an address we no longer hold.
- 2026-10-14 · **Pages also runs privately on hb-5, and the maths site lives there.** At the operator's word, maths.teahub.xyz stays off the internet and is served on hb-5 only. It's the same `pages/server.py`, run from a checkout in `~/local-pages/teahub` under launchd `xyz.teahub.local-pages` and bound to `127.0.0.1:8093` (new `PAGES_HOST`; prod keeps 0.0.0.0). It reads `matcha/maths` straight from the old local Gitea's storage (`file://`, `safe.directory` through `GIT_CONFIG_*`, no token) and pulls every 30 s: `maths.localhost:8093` → `matcha/maths#main/site/public`. The tea-garden page, which existed only in `~/sites/maths`, is now in the repo (maths 08aeaf2). Token 39 (`localpages-20261014`) pushed this and is deleted by id right after; the table is checked. Why: the operator looks at it in the Mac's browser, and a push to the repo should be all it takes.
- 2026-10-14 · **Pages serves byte ranges and media types.** `.mp4`/`.webm`/`.mp3`/`.m4a`/`.wav`/`.zip` get real content types, and a single `Range: bytes=` request gets a 206 (416 when it's out of bounds), with `accept-ranges: bytes` on every file. Safari won't play a video without ranges, and the maths site's tea-garden film is the first video on pages. Token 40 (`range-20261014`) pushed this and is deleted by id right after; the table is checked. Why: video on a pages site should just play.
- 2026-10-14 · **Orgchain: Super Testnet in lineage's clothes, at lineage.yolopreneur.lol/orgchain/.** The same lab and code as supertestnet.lol, restyled with lineage's tokens (concrete, black rule, hazard yellow, monospace) and a rehearsal guide: root, birth (the parent is spent to make each child), generations and badges, as inscriptions; graduation and closing are named as not in the lab yet. Source is branch `orgchain` on `supertestnet/app` (`6d48c5c`; `ORGCHAIN.md` says how to rebuild). The build lives at `ventures/lineage/orgchain/` on time's `gh-pages` (`280d6a8`), and `ventures/lineage/_headers` gives `/orgchain/*` supertestnet.lol's headers while the key tree at `/` keeps its own meta CSP; the key tree's footer links to it. Inscriboor only connects on supertestnet.lol, so the local test wallet is the path here. Checked live in Chrome at 1280 and 390 px, light and dark, through root → birth → recursive inscription: no CSP or script errors and no overflow (the two `net::ERR_ABORTED` preview loads happen on supertestnet.lol too). Token 41 (`orgchain-20261014`, `write:repository`) did the two pushes and was deleted by name right after; the table listing shows only 25 (`time`). It was never printed. Why: the operator asked for lineage's testnet half, matched to lineage's styling.
- 2026-10-15 · **hb-5 is the shell of the old factory, and Boring can show pictures.** The operator's framing: the hb-5 Gitea is the shell of the old factory, where their maths and other experiments live. It isn't a second factory to migrate, and Boring, the operator's admin lane, stays there. So the rule sits at the door: a project that graduates to prod moves with its history, and the copy left in the shell is archived with a pointer. phast, persims, phly, supertestnet, inscriboor and notplanned now carry that sign; persimmons was already archived. Boring's instructions and AGENTS.md, and the shell's matcha/teahub AGENTS.md and docs/self-map.md, now describe this layout. Boring has two new tools that return MCP images instead of text: `boring_mac_screenshot` (Peekaboo; the whole screen or one app's window) and `boring_mac_view_image` (an image under ~/claude/shots or /tmp). They were deployed by matcha/boring's own `deploy-boring-runtime` workflow (source 8742f9c; verification passed, no rollback). That workflow's clone URL had to move from https://teahub.xyz/matcha/boring.git, which is prod now, to the shell at 192.168.5.2:3000. Found on the way: macminid's `use_vision` snapshot hangs and wedges the daemon (restarted twice; avoid it), and matcha/boring `board-tick` has failed every 5 minutes since the move because it reads the old board through https://teahub.xyz (401 on prod). Token 42 (`shell-20261015`) pushed this and is deleted by id right after; the table is checked. Why: the earlier regression came from a second copy with no sign, and an agent that can't see a page can't check it.
- 2026-10-15 · **Orgchain v1 is lineage's app, in lineage's own org.** Super Testnet's kitchen sink becomes the UI for creating and operating lineage holdings: holdings, a tree drawn like docs/lineage.md, and six verbs (found, birth, award, decide, graduate, close), each a `lineage/v0` inscription whose parent is the node that authorizes it. One reducer folds the events into trees and vets every act before it is signed. Super Testnet's auto-miner is now Time: a tempo (each act, 10/30/60 s, or manual), Beat now, and a slider that replays any holding beat by beat. New org `lineage`, repo `lineage/orgchain` (main `6acc319`, Super Testnet's history kept, its engine unchanged). A parallel session's tree work (lab keys, act as any node, graduation by claim + countersign; `2ea7884`, never deployed, paused at the operator's word) is kept there as branch `tree`, to be compared and folded in. The build replaces `ventures/lineage/orgchain/` on time's `gh-pages`, and `/orgchain/*` gets a stricter CSP (`connect-src 'none'`, no frames; the app makes no requests). 43 unit tests; Playwright at desktop and phone sizes through every verb, the clock and replay, also against pages with the real headers. Token 44 (`orgchain-v1-20261015`, `write:repository`) did the pushes and is deleted right after; the table is checked. Why: the operator wanted Orgchain simpler and shaped to lineage (lineage gives the structure, Orgchain adds actions across time), lineage in its own org, and the auto-miner as Time.
- 2026-10-15 · **Tea MCP 2.0: typed tools, pull requests, commits and Actions settings, all as the caller.** `mcp/tea_mcp/server.py` is rewritten (`fb8acb0`, then `fbb1159`): still one file, still acting only with the caller's own Gitea token, now 29 tools. Parameters are typed (patterns, ranges, enums), so a bad argument is refused before Gitea is asked and every limit shows in the tool's schema. New: `tea_pull_get/create/review/merge` (merge keeps the head branch), `tea_labels`, `tea_label`, `tea_commit` (up to 50 files, text or base64), `tea_branch_create`, `tea_repo_edit` (archive included), `tea_hook_create` (one hook per URL), `tea_secret_set` and `tea_variable_set`. Fixed: unknown labels are refused; create or update comes from looking the file up, not from "404" in an error message; org repositories are private by default like user ones; `tea_org_add_member` names its team; `more` and `truncated` come from Gitea's totals; comments page correctly. `tea_actions` had never worked, because Gitea 1.24 has no `/actions/runs`; it reads `/actions/tasks` now. 1.24 has no API that lists a run's jobs either, so there is no log tool yet. The Gitea on hb-5 (28.0.0) has that API, so upgrading prod's Gitea would bring it. 27 tests run against a fake Gitea, and every tool ran once against teahub.xyz in a scratch repo and org, both deleted after. Connectors that still hold 1.0's tool list keep working (2.0.1 also takes `labels` as a string). The old Tea MCP container on hb-5 (`teahub-mcp`, with its Phast sidecar), idle since the cutover, is stopped and set not to restart; it and its volume are kept. Boring's `boring_teahub_*` now operate `green-tea-mcp` (matcha/boring `122f0b3`, shipped by its own deploy workflow). `boring_teahub_deploy` shipped 2.0.1 from the exact main SHA, and status reads that SHA back from the image tag (`fresh: true`). Codex on hb-5 lists `tea` and `boring` as not logged in; `codex mcp login tea` signs it in. Token 43 (`tea-mcp-smoke-20261015`) ran the smoke test and the first push and was deleted by id (the API now answers 401 to it); token 45 (`tea-mcp-201-20261015`) pushed 2.0.1 and this line and is deleted by id right after. Both were `teahubxyz`'s, neither was printed, and the table is checked. Why: #9's audit and plan.
- 2026-10-15 · **Orgchain v1.1: lineage's keys, merged from the tree branch.** The parallel session's key layer (`tree`, `2ea7884`) folds into v1: its `lineage-keys.js` and `handoff.js` come over as written, with their BIP-85, BIP-86 and NIP-06 spec vectors; its off-chain keyring and old UI stay behind, because v1's tree comes from the chain. Each holding gets its own 24-word lab root; every node holds its inscription at its lineage key (BIP-85 org seeds, agents as accounts 1..n of their org's seed, BIP-86 wallets, NIP-06 npubs); every act is signed by whichever key holds the authorizing inscription; graduation is a claim by the org's fresh root countersigned by its derived key, and the derived subtree re-keys under the new root, so the parent's line can no longer sign for it. Labs saved before keys still load and sign with the lab wallet. `lineage/orgchain` main `744c594`; 49 unit tests and Playwright 6/6, keys included. Token 46 (`orgchain-keys-20261015`, `write:repository`) did the pushes and is deleted right after; the table is checked. Why: the operator made this session the lead and asked for the two to be compared and whatever helped used; the tree was the half v1 had left for later, enforcement.
- 2026-10-15 · **Orgchain v1.2: tapkeys and lineage's leaves.** The operator asked for the ssh, git and other keys in Orgchain, and for a tapkey rather than just an npub for each agent. A node's chain key is now its tapkey: its NIP-06 npub with the BIP-86 tweak, so one secret signs its nostr events and its chain spends, and its address follows from its npub (the tweak is checked against BIP-86's own vector). Its leaves hang off the same tree, HKDF-SHA256 with salt `lineage/v0`: an agent's ssh, git, dkim and wg keys from its nostr secret, an org's ssh-ca, mtls and noise keys from its seed. The unit tests hold values read off the key tree page for one mnemonic, and they match byte for byte. Inspect shows each node's tapkey, npub, derivation and leaves, with the public lines to paste (authorized key, `allowed_signers` line, DKIM record, WireGuard peer, CA key). Labs keyed by v1.1 keep their separate m/86' chain keys until they are reset. `@scure/base`, `bip32` and `bip39`, which came in with v1.1, now have their licenses in `public/licenses` and lines in `PROVENANCE.md`. `lineage/orgchain` main `00a3561`, time's `gh-pages` `0984f5a`; 53 unit tests and Playwright 6/6. Token 47 (`orgchain-tapkey-20261015`, `write:repository`) did the pushes and is deleted right after; the table is checked. Why: Orgchain showed lineage's keys only as far as the npub, and the operator wants agents with a key that holds and signs on chain.
- 2026-10-15 · **Taproot and SegWit for every lineage account, listed rather than derived.** The operator asked for Taproot in its own right (it is where inscriptions live, and no one should have to derive it from an npub) and for agents' other public Bitcoin addresses. Every account of an org's seed now has standard addresses at the same index as its NIP-06 key: BIP-86 Taproot for inscriptions and BIP-84 SegWit for payments (0 is the org, whose SegWit branch is its treasury; agents are 1..n). The lineage key tree page derives them on mainnet paths, adds the org's Taproot beside its treasury, and lists agents' addresses in their keyrings and in `lineage.json`; the org rows check against the BIP-84 and BIP-86 vectors, and agent addresses were cross-checked against tapscript. Orgchain v1.3 holds every node's inscription at its BIP-86 Taproot key on test paths (`m/86'/1'/…`) and shows Taproot, SegWit and npub with their paths. v1.2's tapkey (the npub's key with the BIP-86 tweak) is retired; labs keyed by v1.1 or v1.2 keep their keys until reset. Proposed for spec v0.1 in `docs/lineage.md`. `lineage/orgchain` main `0af51dc`, time's `gh-pages` `7e08cc5`; 54 unit tests and Playwright 6/6. Token 49 (`lineage-btc-20261015`, `write:repository`) did the pushes and is deleted right after; the table is checked. Why: inscriptions live at Taproot addresses, and an agent's addresses belong in what it publishes.