Files
teahub/AGENTS.md

8.9 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. queued runs it when its turn comes (oldest first, Depends on #N respected); ready runs it on the next beat; spec has Time split it.
  • A card is what a Terra worker finishes in forty turns. Larger work is a parent labelled planned with children that carry their own DONE: lines; a parent is never queued. 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: #N names a PR that already answers the card, so Time reviews it instead of building again.
  • Before a task, find its route in SKILLS.md and load only the skills it names, by path. No model decides which skill to load.
  • You act as yourself (Time too: it is the time user). 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.md saying 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 with fly 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.py the clock, venture.py the venture loop, astra.py the daily planner, router.py its ranking, housekeeping.py the daily sweep, sync.py copies on other forges (time/sync.json: one home, one writer per branch; main out fast-forward, claude/* branches home as PRs), seats.json the seats). Spend pools (expiring credit, refilling windows) are time/pools.json. Its SOPs: .agents/skills/<name>/SKILL.md in that repo. The planner, the steward and housekeeping all write to the "Astra log" issue there (time#57).