Router: money left is the worker pool's allowance; no repeat cards (#181)
money_left(): the allowance left in the pool that takes TIME_WORKER's route, else the daily cap's remainder, capped by the month's. The seat sees cards closed in the last 14 days; a new card repeating an open or lately closed one is not written.
Closes#175.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017K4vyY3yUD3GsvoZaAtKkD
Sync: a repo's copies on other forges follow its home (#177)
sync.py + time/sync.json + the sync workflow. One home per repo, one writer per branch: main goes out to every copy
fast-forward only (a diverged copy is a needs-human issue, never overwritten, unless forced once); a copy's claude/*
branches come home as PRs for the council. First copy: github.com/teahubxyz/time, skipped until GITHUB_MIRROR_TOKEN.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017K4vyY3yUD3GsvoZaAtKkD
Adaptive budget: pace spend to each capacity pool (#174, re-cut of #167)
The worker's #82 change (sonnet via Time): budget_check(route) paces each call to its capacity pool in
time/pools.json (expiring credit spread over the days left, refilling windows, or TIME_DAILY_USD without a pool);
the monthly cap stays hard. pools.json is read through the API once per run, since every workflow checks out only
.github/time. Ships empty: nothing changes until it is filled in. Closes#82.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017K4vyY3yUD3GsvoZaAtKkD
Router v1: the factory ranks its own next work, dry to start (#169)
Astra's seat judges every candidate (kind, value, size); router.py ranks them with the owner's weights per kind
(time/router.json), a restless boost and card age. dry posts the table; live queues from the top within the day's
money and the heartbeat promotes queued cards in ranked order. Astra reads the last 14 days of its log. Closes#168.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017K4vyY3yUD3GsvoZaAtKkD
venture: the lead (opus) researches and picks the day's venture alone; fable is out (#164)
One seat, TIME_VENTURE_LEAD (opus), runs the day's venture: a research round over the top trending repos (with the
start of their READMEs) and the studio's track record, TIME_VENTURE_FIELD candidates with a verdict each, one pick;
no pitches, no vote. It writes the launch plan alone and judges the build, and hands the launch drafts to its helper
(TIME_VENTURE_HELPER, sonnet). The chair and judge default to opus. Batches keep the board; TIME_VENTURE_LEAD=board
brings it back for the daily venture. Closes#165.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017K4vyY3yUD3GsvoZaAtKkD
venture: one venture a day, built for quality (#162)
The day's card starts only once every other venture card is launched or held; the board picks one from a field of
TIME_VENTURE_FIELD (6) pitches; opus builds; the judge scores the product 1-10 and a page under TIME_VENTURE_BAR (8)
gets polish rounds (never the last of TIME_VENTURE_FIXES=3), then launches with its score. An open batch card with
no Time beats no longer starts a batch while batches are off. Closes#163.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017K4vyY3yUD3GsvoZaAtKkD
venture.yml: install Chromium for the browser pass (#157)
The first Claude ventures launched without the browser pass (no Chrome on the runner): no headless checks, no
contact sheet for the portfolio. One step installs Chromium in the job image; venture.py's chrome() finds it.
Merged on the owner's word, CI green (run 1014).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017K4vyY3yUD3GsvoZaAtKkD
venture.yml: every 6 hours, Claude seats (#141)
Owner's call: the venture loop runs every 6 hours instead of every 20 minutes, on the Claude seats.
The builder is vars.TIME_VENTURE_WORKER || claude:sonnet, decoupled from the heartbeat's worker.
Merged on the owner's word after the council approved the engine half (#140).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017K4vyY3yUD3GsvoZaAtKkD
Workflows batch: heartbeat knobs, housekeeping.yml, its test in CI (#127)
heartbeat.yml passes TIME_CAP_SLACK, TIME_ANTHROPIC_API (the caching kill switch), TIME_REVIEW_TIEBREAK and TIME_REVIEW_QUORUM; housekeeping.yml runs the daily sweep at 13:17 UTC; ci.yml runs test_housekeeping.py. Owner-approved merge.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017K4vyY3yUD3GsvoZaAtKkD
checks(): a status from one of Time's own workflows is not a check (#124)
A seat's review wakes heartbeat.yml during a heartbeat; the concurrency group cancels the run and Gitea records it as a failure on the PR head. Those statuses neither block nor earn a merge; CI decides. Owner-approved merge.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017K4vyY3yUD3GsvoZaAtKkD
labs/aicharts: fast mode (Clef first, LLM checks) as demo default (#42)
Opened 2026-10-14 by a Claude Code session under the owner's login, which is why it read as the operator's PR for three days. Lab-only and reversible: Clef-flash draws first, the LLM checks in parallel, the chart is redrawn only on disagreement; API callers keep the LLM default. The lab's tests pass on the branch (run 652, "aicharts: all good"); its deploy step cannot run from prod, which holds no Cloudflare secrets, so nothing is deployed by this merge.
Squash-merged by the CEO session on the owner's explicit instruction.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017K4vyY3yUD3GsvoZaAtKkD
One Gitea user per seat (model line); the reviewer's verdict becomes a real review by that seat's own user once #76 lands. TIME_SEAT_CLAUDE stays until then as the umbrella.
On the owner's explicit instruction (CEO session).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017K4vyY3yUD3GsvoZaAtKkD
TIME_PROTECTED governs every protected path except the workflow directories (#81)
touches_protected() hard-coded all of .github/ and .gitea/ on top of TIME_PROTECTED, so the engine under .github/time/ could never land without a human. Only the workflow directories stay hard-coded; DEFAULT_PROTECTED is unchanged. With this repo's TIME_PROTECTED narrowed, card PRs under .github/time/ with a trusted Approve and green checks merge via the time bot.
CI green on 3b757fa. Squash-merged by the CEO session on the owner's explicit instruction.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017K4vyY3yUD3GsvoZaAtKkD
The job timeout moves from 20 to 55 minutes: workers can overlap inside one run (#75), and at 20 every in-flight worker died together. TIME_SEAT_CLAUDE reaches the heartbeat so the reviewer can post as the `claude` user once #76 lands; until then it is unused.
Both on the owner's explicit instruction (CEO session).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017K4vyY3yUD3GsvoZaAtKkD
time/worker-run cd .github/time && sed -n 80,150p test_time.py; sed -n 455,480p test_time.py; grep -n "claude-sonnet
Objections go back to the worker, with the review attached (#59)
Revise loop for `/time retry`: an open PR's reviewer comments go to the worker on the same branch, open_pr updates the open PR, the card returns to `dispatched`, and verdicts older than the last revision no longer count. Check 55 covers it.
Reviewed: Approve by Time's reviewer (haiku); the two confirmation points answered by the steward. Merged by the CEO session on the owner's explicit clearance after eleven steward sign-offs were blocked by a session permission guard.
Closes#53
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017K4vyY3yUD3GsvoZaAtKkD
Co-authored-by: Time <time@users.noreply.teahub.xyz>
time/worker-run git fetch origin gh-pages 2>&1|tail -1; git show FETCH_HEAD:ventures/dollhouse/app.js | sed -n 140,3
seed: land a venture built elsewhere on yolopreneur.lol (#64)
Actions -> seed -> Run workflow with a slug, the URL(s) of a .tgz whose top folder is the slug, and its sha256
(plus a name and a one-liner for a new venture). seed.py checks the bundle, copies it over ventures/<slug>/ on
gh-pages in one commit, adds or refreshes the venture's line in ventures/ventures.json, and the workflow asks
Teahub pages to pull. Nothing in the bundle runs. test_seed.py runs in CI. Merged at the owner's request.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K9wtGiGEeq1H5DA3T88PRe
Closes#51
Merged by Claude for the operator (the delegated merger for engine PRs). Reviewer objection answered on the PR: CI was green; the reviewer cannot see checks yet (#52).
Co-authored-by: Time <time@users.noreply.teahub.xyz>
Co-committed-by: Time <time@users.noreply.teahub.xyz>
time/worker-run python3 - <<'EOF'
p=".github/time/test_time.py"
s=open(p).read()
old='import concurrent.futures as c
Gitea 1.24 also refuses the Actions identity label edits (removing a label is a 500), which crashed
promote_next and stalled the queue. gh() now uses TIME_TOKEN for every write except comments (Time's
beats are gitea-actions' comments) and commit statuses; the time user never counts as trusted and
mention replies ignore it; astra.yml gets TIME_TOKEN.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017fTCFiw6ohysUDcWoPsTys