Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017K4vyY3yUD3GsvoZaAtKkD
8.7 KiB
8.7 KiB
AGENTS.md — Teahub v1 (Green Tea)
You are on prod: https://teahub.xyz, Gitea 28 on Fly (app green-tea, configured by gitea/fly.toml, its look in gitea/custom). Everything here is the factory's own
record; nothing here is scaffolding from before 2026-10-14.
you (any agent) ──MCP──▶ mcp.teahub.xyz ──as the signed-in user──▶ teahub.xyz (Gitea)
│
login: GitHub (now), nostr (next) ├── teahubxyz/teahub the spine (this repo)
├── teahubxyz/time Time: the clock (Gitea Actions on the Fly runner)
└── <your repos>
Time = the automation layer. It lives here, on prod (teahubxyz/time); the GitHub copy is an archived proof of concept.
Time acts as the Gitea user `time` (its own token, TIME_TOKEN) for every write except comments and commit statuses,
which stay with the Actions identity (`gitea-actions`); code goes in as git pushes. Seats post as themselves: a
review by `haiku` is a Gitea review by the user `haiku` (one Gitea user per model line, TIME_SEAT_<SEAT>).
Rhythm: Astra (daily, 13:13 UTC) is the router: its seat judges every candidate card (kind, value, size) and
`router.py` ranks them with the owner's weights per kind in teahubxyz/time's `time/router.json` (mode dry: it posts the ranking on
the Astra log; live: it queues from the top and the heartbeat promotes in ranked order). The heartbeat (hourly, and on demand) builds `ready` cards with a
seat, gets each PR reviewed by the council, and merges on approve + green CI, engine code included. Only the workflow
directories (`.github/workflows/`) stay a human's merge: the CEO batches them. A card whose PR already exists (Codex, a
chat, the CEO) is adopted: labelled `ready`, it is reviewed and landed, never rebuilt. Housekeeping sweeps daily (13:17).
Ventures: paused since 2026-10-19 (TIME_VENTURE=off; the launched ones are still measured) until the router starts
them (time#170). When on: one a day, built for quality; the day's card starts once every other venture card is launched or held. Opus leads alone: a research round over the trending repos and the
studio's track record, one pick, the plan, the build (`claude:opus`) and the judging (a 1-10 score: under 8 earns
polish rounds, then it launches with its score); sonnet drafts the launch posts. No fable. Batches (off) keep the board. Each venture lives at <slug>.yolopreneur.lol (gh-pages `ventures/<slug>/`); the
portfolio at yolopreneur.lol is gh-pages `ventures/index.html`, made by hand, and reads `ventures.json`.
Seat workers (and the venture builder) carry Ponytail's rules (time `.github/time/rules/ponytail.md`); reviewers don't.
Tiers: Luna = haiku (Codex: luna), Terra = sonnet (terra), Sol = opus (sol), Astra = fable (astra), the C level. Venice
seats (kimi, grok, ...) break ties. The operator hears from the Astra tier only on exception or check-in.
Spend: every model call is booked to time/ledger/<YYYY-MM>.jsonl, cached tokens priced. TIME_MONTHLY_USD=100 is the
owner's envelope; TIME_DAILY_USD (15) paces it and gates launches; a run launched within budget finishes (1.5x). A
breach opens an `andon` issue. No model decides whether to spend.
hb-5 (the Mac) is NOT part of prod: it is the operator's playground and the old instance (matcha.teahub.xyz).
Boring (ops MCP) lives on the Mac and may reach prod as a client; prod never depends on it.
Moves
- Read first: this file,
docs/decisions.md(why things are the way they are),docs/rebuild.md(what it took). - Work is a card: an issue with a
DONE:line. Open it, do it, receipt it on the issue, close it.queuedruns it when its turn comes (oldest first,Depends on #Nrespected);readyruns it on the next beat;spechas Time split it. - A card is what a Terra worker finishes in forty turns. Larger work is a parent labelled
plannedwith children that carry their ownDONE:lines; a parent is neverqueued. Three cards died at the turn ceiling before this rule. - A card says where it lives.
Base: <branch>(every venture card:Base: gh-pages) makes the worker cut its branch from there and open the PR against it; without the line, the default branch.PR: #Nnames a PR that already answers the card, so Time reviews it instead of building again. - Before a task, find its route in
SKILLS.mdand load only the skills it names, by path. No model decides which skill to load. - You act as yourself (Time too: it is the
timeuser). There is no shared service token on prod. If you can't do something, your Gitea permissions are the reason; ask the owner (teahubxyz) on the issue. - Porting from the old instance: only when a card needs it, only after reading it, one piece per commit, and a line in
docs/rebuild.mdsaying what it took. - Secrets: prod holds Gitea's own keys, the GitHub OAuth client, the MCP's OAuth client, and the seat keys listed in
docs/decisions.md. Nothing else. Do not add one without a decision there. A temporary admin token is deleted (sqlite3 on the Fly box) and the deletion checked before you write that it's gone. - Be boring by default; get clever only on an ANDON. Deterministic scripts before cheap inference before expensive inference.
Situations
What to do when you meet one of these. Each row names the procedure; the procedure names the skill or the code.
| You see | Do |
|---|---|
A ready card with no worker yet, and a PR already answers it |
Nothing: Time adopts the PR on its next beat (a pr beat with adopted: true). Make sure the PR body says Closes #N or the card says PR: #N. |
The reviewer objected; the PR is needs-human |
Read the objection on the PR. If it is right and small, comment /time retry on the card: the worker gets the review text and answers on the same branch. If it is wrong, say so on the PR as yourself (Approve/Object comments from trusted users count) and remove the label. |
A PR is approved but mergeable: false |
It fell behind its base. Until time#123 lands, a human re-cuts the branch from the base and re-applies the change (or merges the base into the branch); a Closes #N line keeps the card's adoption. |
| A worker stopped at the turn ceiling ("stopped without a PR after N steps") | First check the card's Base: line (a venture card without Base: gh-pages cannot find its files). Then split the card; never retry the same card unchanged twice. |
An open venture card whose history is comments by a person, not gitea-actions (the GitHub-era cards, migrated) |
Close it. Time counts only its own beats, so the loop takes such a card as unstarted and pitches a new venture on it (batch time#26 was reused that way on 2026-10-18). The venture itself stays in ventures.json. |
An andon issue: spend cap reached |
Read the ledger for the day. The daily cap is pacing (the CEO may raise it with the owner's OK; log it in docs/decisions.md); the monthly cap is the owner's alone. Close the andon once handled; Astra queues nothing while one is open. |
A PR head shows heartbeat / tick: failure |
Not a check. Time's own workflow statuses (heartbeat, mention, venture, astra, doctor, update, steward) are ignored by the merge gate (time#124). CI decides. |
| Housekeeping posted a stale list on the Astra log | Follow .agents/skills/housekeeping/SKILL.md in teahubxyz/time: decide each needs-human, idle PR, parked or error card. Housekeeping never acts on the list itself. |
| A workflow file needs to change | Open the PR, label it needs-human, and note it on the Astra log. The CEO merges workflow files in a batch; nobody else, and never through a side channel. |
| A card touches money or a human-only step (a purchase, a signature, a Whop upload) | Stop at the step, write what is ready and what is needed on the card, and escalate to the owner. Everything up to that step still gets done. |
| You want a new skill, or a vendored one changed | SKILLS.md → Moves. One PR with the skill, its katas and a ledger line. |
Where things are
- MCP source:
mcp/(FastMCP, deploy withfly deploy). - Decisions:
docs/decisions.md(append-only, dated). - Rebuild log:
docs/rebuild.md. - Skills:
SKILLS.md(routes, ledger, belts); the vendored folders are in.agents/skills/. - Time's engine:
teahubxyz/time.github/time/(time.pythe clock,venture.pythe venture loop,astra.pythe daily planner,housekeeping.pythe daily sweep,seats.jsonthe seats). Its SOPs:.agents/skills/<name>/SKILL.mdin that repo. The planner, the steward and housekeeping all write to the "Astra log" issue there (time#57).