Commit Graph
30 Commits
Author SHA1 Message Date
Claude cb40eb869e Integrate batch 5: five rebased branches landed as one
ci / test (pull_request) Successful in 1m8s
The five branches each worked alone against an older `main` and conflicted
with it and with one another. Merged one at a time, every conflict resolved
by keeping both sides' behaviour, with all three suites green after each
merge. Nothing was left out.

Where the two sides met:

- `promote_next` (#286 against #245/#285): it fills every free slot in one
  pass and returns the cards it started, and a card waiting on a person now
  reaches only the cards that wait on it — the stalled `ready` cards hold no
  slot, their specs get one andon note each, and the gate reads the open
  dependencies through `waits_on` so the log says what each held card waits
  on. `deps_met` stays for the callers and tests that read it directly.
- Astra's picks with no card (#281 against #282): the key decides. A
  `venture:` pick is dispatched or written by `start_venture`; anything else
  is one of the records' own `opt:` findings and is written as a card. Both
  show up in the beat (`started`, `opt`), in the live lines and in the dry
  run, and `router.table` says "would be written as a card" only for an
  `opt:` key, so a venture still reads as "would queue".
- `router.py`'s candidate docstring and the two additive candidate sections
  (#170's `new_venture`/`v2_candidates`, #171's optimization sources) both
  kept.
- README and CHANGELOG keep every side's lines.

Tests: both sides' blocks are kept and run — 80, 135/245/247, 170, 171, 172,
astra 1-3, 79/79b/79c/79 handoffs. #286's `promote_next` assertions were
rewritten to the list shape the parallel scheduler returns; nothing was
dropped.

`python3 .github/time/test_time.py`, `test_seed.py` and `test_housekeeping.py`
all pass. No file under `.github/workflows/`, no secret and no deploy file was
touched.

Includes #286
Includes #281
Includes #282
Includes #290
Includes #291

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FAqjv1mK1ziVNiYsn1CFbY
2026-10-29 20:37:57 +00:00
Claude 2325dc6a00 Merge remote-tracking branch 'origin/claude/card-247-needs-human-scope-vbi95b' into claude/integrate-batch-5-1p4lwf
# Conflicts:
#	.github/time/test_time.py
#	.github/time/time.py
#	README.md
2026-10-29 20:30:55 +00:00
Claude 2f99c21c24 Merge origin/main into card #247: a stall's scope meets the planner's Depends on: lines
ci / test (pull_request) Successful in 1m22s
Six commits landed on main while this card was open (#283 the router's loud
no-op, #284/#244 the planner's coarse cards, #289/#277 a card branch is never
rewound, #292/#80 the steward inside Time). Only `.github/time/time.py`
conflicted; CHANGELOG.md, README.md, SKILL.md and test_time.py merged with both
sides' lines.

- `DEPENDS`: main's `re.compile(r"Depends on:?[ \t]*#(\d+)", re.I)` (#244) is the
  one definition. This card had added a narrower `Depends on #(\d+)` of its own
  further down the file, which as the later binding would have won and stopped
  the new planner's `Depends on: #N` lines from being read at all — and broken
  main's own assertion that `DEPENDS` matches both forms. Removed; `deps_of` now
  reads both, so cards filed before #244 still wait on the right ones.
- `promote_next`: this card's body is kept, since `waits_on` is the inline
  dependency check main edited, lifted out and given the `known` cache and the
  log line. Main's only change there was swapping that `re.findall` for
  `DEPENDS.findall`, which `deps_of` now does.
- `WAITING` gains `parked`. Main's #277 added a fourth way for a card to wait on
  a person: its branch is gone from under an open PR and someone must push it
  back. It keeps its `ready` label, so without this it would have held a
  TIME_PARALLEL slot until a human arrived — exactly the stall #135 removed and
  this card scopes. Now it frees its slot, holds only the cards that wait on it,
  and its spec gets the andon note, with the PR named from the `parked` beat's
  own `pr`. Tested in the #135 block of test_time.py.

test_time.py (66 blocks, test_steward.py included), test_seed.py and
test_housekeeping.py all pass. test_delegate.py fails identically on
origin/main (`World.http()` takes no `headers`): pre-existing, untouched here.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FAqjv18qYU68gMq5nsc1Xq
2026-10-29 19:53:30 +00:00
Claude bac994eb78 Merge origin/main into card #79: mentions-as-handoffs beside the landed siblings
ci / test (pull_request) Successful in 1m29s
main brought the steward tick (#292/#80), the planner's 4-6 coarse cards with
their `Depends on:` lines (#284/#244), the loud-no-op router (#283/#211) and the
"a card branch is never rewound to its base" guard (#289/#277). This branch
brings `@codex`/`@claude` as seats with hands and the handoff chain (#79).

Only README.md conflicted, in the feature list: the Mentions bullet is this
branch's (codex, claude, the handoff chain), the Hands-off bullet is main's
(4 to 6 cards, each with what it waits on). Both bullets are kept.

CHANGELOG.md merged under the union driver, so both sides' `### Added` lines
stand. `time.py` and `test_time.py` auto-merged in disjoint regions and were
checked for integration rather than text: `codex_push` pushes with the seat's
own token through its own git calls, so main's new `create=False` gate on
`git_commit` (and `Hands._commit`) does not touch it; `book(model, usage,
**extra)` still takes main's callers unchanged while codex books `pool`/`launch`;
main's new `pull_cord`/`park`/`BranchGone` sit clear of the seat code; and no
definition from either side was dropped.

test_time.py (both sides' markers, `ALL OK 79 handoffs` and `ALL OK 277` /
`ALL OK steward` among them), test_seed.py (3) and test_housekeeping.py (10)
all pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FAqjv1AEsy9dHGKjivMsvS
2026-10-29 19:51:51 +00:00
Claude 7340596d10 Merge main into #245: the parallel scheduler reads the planner's Depends on: lines
ci / test (pull_request) Successful in 1m42s
Four sibling cards landed on main under this branch (#244 the planner, #283 the
router's no-op judge, #289 the branch rewind, #292 the steward inside Time). Two
files conflicted, and both sides' behaviour is kept.

- `promote_next` stays this branch's one-pass fill: it labels every free slot's
  worth of dependency-ready `queued` cards `ready` (the router's live ranking
  first, else oldest), returns the list it started, and prints
  `promote: ready=N moving=M free=F`. Main's single-card version, which returned
  one number and read the dependency line inline, is gone.
- The gate takes main's side on the dependency line: `deps_met` now matches with
  the shared `DEPENDS` pattern instead of its own `Depends on #(\d+)`, so the
  `Depends on: #N` lines #244's planner writes hold a card back as well as a
  hand-written `Depends on #N`. Without this the two cards cancelled out — the
  planner wrote a line the scheduler could not read, and every card of a planned
  spec looked free to start at once (main's own heartbeat test at test_time.py:333
  catches it). The memoisation across the pass is unchanged.
- astra.py's header keeps this branch's description of the heartbeat (parallel
  promotion, up to TIME_PARALLEL) with main's `Depends on: #N` spelling.
- test_time.py (section 245): both spellings gate, and one pass reads a shared
  dependency once rather than once per card.
- CHANGELOG.md keeps both sides' lines. The #245 entry's closing sentence, that a
  spec Time plans itself still chains card on card until the planner stops writing
  `Depends on #N` for every step, was written while #244 was open and is now
  false: #244 has landed, so the entry says instead that a planned spec opens with
  every card that waits on nothing. README's heartbeat line takes the same
  spelling.

test_time.py, test_seed.py and test_housekeeping.py all pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FAqjv1FxvvoAsdTCXtto8G
2026-10-29 19:51:42 +00:00
Claude da08f3c892 Mentions are handoffs: @codex and @claude dispatch headless seat runs as their own users (#79)
ci / test (pull_request) Successful in 1m0s
Two seats beside @sonnet, @opus, @kimi..., neither of them in seats.json:

- `@codex <ask>` runs a headless `codex exec --sandbox workspace-write --json` in a
  throwaway checkout cloned with `TIME_SEAT_CODEX`, under a wall-clock cap
  (`TIME_SEAT_RUN_MINUTES`, default 15; the process group is killed at it and nothing
  is pushed). Its last message is the reply, posted as `codex`. Work left in the tree
  is committed as `codex`, pushed to `codex/issue-N-<stamp>` with the seat's token, and
  the PR is opened as `codex`. The CLI's environment drops `TIME_*`, `ACTIONS_*`,
  `LANGFUSE_*`, `GITHUB_TOKEN` and the model keys, so the seat's hands never see Time's
  secrets, its own token included; `TIME_CODEX_MODEL` picks its model.
- `@claude [haiku|sonnet|opus|fable] <ask>` runs a Claude seat (opus by default) with
  the repo context Time already assembles for reviews (the README, and on a PR its diff
  and checks) and posts as `claude` via `TIME_SEAT_CLAUDE`.

Without the seat's token, or if Gitea refuses the comment, Time posts for it as before.
Every posted reply is signed `<sub>codex via Time · <model></sub>`.

A reply whose last line starts with another seat's @mention is a handoff: Time runs that
seat on the reply, with no human between the stages. `@a x -> @b y -> @c z` is a chain of
stages (arrow: `→`, `->`, `=>`); several seats in one stage, or on separate lines, run
side by side, as the launcher's grammar already read them. `TIME_HANDOFF_MAX` (default 6)
bounds the seat runs one comment may set off, so a ping-pong ends. No one hands off to
itself, and a mention mid-sentence is still just a mention.

Budget: `codex exec` books one ledger line (`pool: codex`, `launch: 1`, tokens from its
`--json` events, `usd` null -- no price) and is paced by `budget_check("codex")`; the
Claude seat books like every other call. Strangers' mentions are ignored as today.

Tests in test_time.py (`ALL OK 79 handoffs`): the grammar and the handoff rule;
`codex_clone`/`codex_push` against a real bare repo (the token rides the URL, never
.git/config); a trusted `@codex` comment launching the runner with the seat token,
committing and opening the PR as codex, and posting as codex; a stranger's doing
nothing; a reply ending in `@claude ...` dispatching the next seat; an arrow chain
running claude -> codex -> haiku, each stage reading the last; a ledger booking per run;
the wall-clock cap tripping cleanly; the handoff limit; a missing token, a spent budget
and a refused comment.

WORKFLOW CHANGE FOR THE OPERATOR (.github/workflows/ is a protected path, so this
commit stops at the code). In `.github/workflows/mention.yml`:

    -    timeout-minutes: 8
    +    timeout-minutes: 25   # above TIME_SEAT_RUN_MINUTES (15) plus the clone and the handoffs
         steps:
           - uses: actions/checkout@v5
             with:
               sparse-checkout: .github/time
    +      - run: npm install -g @openai/codex@0.159.2   # `@codex` runs the CLI headless
           - run: python3 .github/time/time.py mention
             env:
    @@
               TIME_DAILY_USD: ${{ vars.TIME_DAILY_USD }}
               TIME_MONTHLY_USD: ${{ vars.TIME_MONTHLY_USD }}
    +          TIME_SEAT_CODEX: ${{ secrets.TIME_SEAT_CODEX }}     # the `codex` Gitea user's token
    +          TIME_SEAT_CLAUDE: ${{ secrets.TIME_SEAT_CLAUDE }}   # the `claude` Gitea user's token
    +          CODEX_API_KEY: ${{ secrets.CODEX_API_KEY }}         # or OPENAI_API_KEY: codex's own auth
    +          TIME_SEAT_RUN_MINUTES: ${{ vars.TIME_SEAT_RUN_MINUTES }}
    +          TIME_HANDOFF_MAX: ${{ vars.TIME_HANDOFF_MAX }}
    +          TIME_CODEX_MODEL: ${{ vars.TIME_CODEX_MODEL }}

Until that lands, `@codex` answers "no TIME_SEAT_CODEX secret on this repo yet" or
"`codex` is not installed where this workflow runs", and `@claude` posts as Time.

Closes #79

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FAqjv4VTrzR61LLc4ifsjZ
2026-10-29 18:55:48 +00:00
Claude 8c47b23861 Scope a needs-human stall to its dependents and say so on the spec
ci / test (pull_request) Successful in 1m10s
A card parked for a person (`needs-human`, `error`, `stuck`) already held no
slot (#135), but nothing said what the factory was waiting on and the scoping
was buried in an inline dependency check. Now it is explicit and said once:

- `stall_of(card)` returns the beat a ready card is parked at (None while it is
  moving); `moving()` is that answer inverted.
- `deps_of`, `waits_on` and `dependents` name the dependency graph `promote_next`
  already walked: a queued card is held only while a card it waits on is open,
  so a stall holds the chain behind it and nothing else, and the heartbeat log
  prints the dependency each held card waits on. A dependency Time can't read
  still counts as open, and the open `ready`/`queued` rows in hand are reused
  instead of refetched.
- `andon_note(card, beat, queued)` comments once on the card's spec
  (`Part of #N`) naming the card, the beat it stalled at, its PR, the cards held
  behind it (transitively) and that everything else keeps moving. The note is
  keyed on the card and the beat's timestamp, so the hourly heartbeat does not
  repeat itself and a card that is retried and parks again is said again. No
  `andon` label is set: that would stop Astra planning, which is the opposite of
  keeping the queue moving. A card with no spec gets no note.

Tests (#247 in test_time.py): with #244 parked at needs-human, #245 and #246
(which waits on it through #245) stay queued while the independent #250 starts;
the spec gets one comment naming the blocker and what is held behind it; a
second beat adds no second comment; a second stall is said again; and once #244
closes, #245 starts.

test_time.py, test_seed.py and test_housekeeping.py pass. test_delegate.py
fails on main too, untouched by this card (World.http() takes no `headers`).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FAqjv5X4dnqh4zPDe99AHj

Closes #247
2026-10-29 18:55:30 +00:00
Claude c2124f4d7a Planner: 4-6 coarse cards per spec, each with its Depends on: lines
ci / test (pull_request) Successful in 1m11s
The planner asked its seat for "small cards, one pull request each" and
chained whatever came back: card 2 waited on card 1, card 3 on card 2,
however little the work actually needed. A spec became a long single file
of thin cards, and with TIME_PARALLEL at 3 (#243) two of the three slots
sat empty.

- PLAN_PROMPT asks for 4 to 6 cards, each shippable on its own (a module
  and its tests, a group of endpoints, a schema and its migration), and
  for `depends_on`: the positions in the list a card can't start without.
- plan_deps() maps those positions to the cards already filed, dropping a
  reference to itself or to a later step. A seat that says nothing falls
  back to the step before it, so a human's `- title — DONE: x` lines keep
  the order they were written in.
- Every card carries what it waits on: one `Depends on: #N` line per card,
  or `Depends on: none`. The planned comment names the cards nothing
  blocks.
- time.py's promote_next and router.py's candidates() read both the new
  line and the older `Depends on #N`, so cards filed before this still
  wait on the right ones (#184).

Tests: the planner's own checks now assert the line on every card; a new
seat-plan check (two cards free, three waiting) ends with both free cards
promoted and dispatched in one heartbeat, and a router check reads a card
that carries one line of each form.

No workflow change needed.

Closes #244

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FAqjv1tfHenkbKtJZkZ52r
2026-10-29 18:53:45 +00:00
Claude f7ee459946 Scheduler: start dependency-ready cards in parallel up to TIME_PARALLEL (#245)
ci / test (pull_request) Successful in 1m28s
One heartbeat started one card. `promote_next` labelled the single best `queued`
card `ready` and the run dispatched it, so cards that waited on nothing still
went one behind the other, however many slots TIME_PARALLEL allowed.

- `promote_next` fills every free slot in one pass and returns the cards it
  started: the best `queued` cards whose every `Depends on #N` card is closed
  (the router's live ranking first, else oldest first), up to TIME_PARALLEL in
  flight at once. The same heartbeat dispatches them, so independent cards build
  at the same time.
- `deps_met` is the gate, with the dependency lookups memoised across the pass
  (the cards of one spec tend to name the same dependency). A card whose
  dependency is still open stays `queued` however free the slots are.
- The cap counts the cards already in flight, and only the ones that are moving
  (#135): two against a cap of three leaves one slot, a full cap starts nothing,
  and TIME_PARALLEL=1 is the old one-at-a-time chain. The log line is now
  `promote: ready=N moving=M free=F`.
- Tests (test_time.py, sections 80 and 245): the gate (a card behind an open
  dependency is never started, and starts once that card is closed), the cap
  arithmetic at 1/2/4/5 slots against three cards in flight, and whole
  heartbeats that leave two and then three cards building at once.
- README, CHANGELOG and astra.py's header say what the heartbeat now does.

Not in this card: a spec Time plans itself still chains card on card, because
`plan_spec` writes `Depends on #<previous>` for every step. #244 is the card that
stops that; until it lands, parallel starts show up on cards whose dependencies
are written by hand (or absent). No workflow change is needed for this card.

test_time.py, test_seed.py and test_housekeeping.py are green. test_delegate.py
fails on main before this change too (its fake `World.http` takes no `headers`
kwarg, which the Messages API call passes); it is untouched here.

Closes #245

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FAqjv5NCpnmkuxczozbcDU
2026-10-29 18:53:28 +00:00
time af15cf16b0 Add TIME_PARALLEL config setting (default 3) (#248)
time/worker-run cd .github/time; python3 - <<'E' p='time.py'; s=open(p).read() s=s.replace('''PLAN_PROMPT = """Split
ci / test (push) Successful in 47s
sync / sync (push) Successful in 8s
ci / test (pull_request) Successful in 46s
heartbeat / tick (pull_request_review) Successful in 12s
Co-authored-by: Time <time@users.noreply.teahub.xyz>
2026-10-22 20:07:56 +00:00
teahubxyzandClaude Opus 5.5 e705ca00ac refresh: rebuild a gh-pages venture in place, from its own tools/build.sh (#67)
ci / test (push) Successful in 34s
refresh: rebuild a gh-pages venture in place, from its own tools/build.sh (#67)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012sekpYMwTXuMdza1isMQA1
2026-10-16 05:18:37 +00:00
teahubxyzandClaude Opus 5.5 721212ba7e seed: land a venture built elsewhere on yolopreneur.lol (#64)
ci / test (push) Successful in 35s
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
2026-10-15 23:56:46 +00:00
teahubxyz 6bf0b0411b README: Claude seats and the spend governor
ci / test (push) Successful in 36s
2026-10-14 19:32:32 +00:00
teahubxyz c360639456 Port: Time runs on Gitea (teahub.xyz) (#47)
ci / test (push) Successful in 35s
2026-10-14 06:55:19 +00:00
teahubxyzandClaude bc6f232a56 venture batches: the board's top k as one milestone, launched together (multi-ceremony) (#22)
One batch card scouts once, the seats pitch a field, and the board ranks it; the top k
(each wanted by two seats) become venture cards in the batch's milestone at 'picked'.
Children run the ordinary loop side by side, wait at 'ready' until every sibling is
settled or the hold runs out, then launch together. No child left behind: one batch
retry for a held child, then it is counted dead in the cohort retro, which closes the
card and the milestone. Fix rounds now yield the single worker run per tick to cards
still due their first build, so a failing page can't starve its siblings.


Claude-Session: https://claude.ai/code/session_01VDkN7ukK1kXkqov8FaZxva

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-13 01:20:49 +00:00
Claude c54cbf2596 venture backends: accounts with passkeys
Each venture's Worker can now sign people up and in with passkeys (WebAuthn):
no passwords, no email, no OAuth app, nothing to configure. The relying party
is the venture's own host and the session a __Host- cookie (HttpOnly, Secure,
SameSite=Lax, 30 days), stored hashed in the venture's D1 database. ES256 and
RS256 keys; challenges are single-use and expire in five minutes; origin,
relying party, user presence and the signature counter are checked; auth
endpoints refuse cross-origin calls. Items saved while signed in are recorded
as that person's, and /api/me/items lists them.

time.js gains Time.accounts, user, signUp, signIn, signOut and mine; builds
are told to use them for what the paid tier promises and never to put sign-in
in front of the free product. test_auth.mjs runs the whole ceremony against a
real SQLite and a software authenticator, including replay, phishing origin,
another site's passkey, a cloned counter, a tampered signature and a duplicate
registration; CI pins node 22 so it runs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wyb3QQDESFkosKRXzrXqwr
2026-10-12 18:46:56 +00:00
Claude 134a03ce41 venture backends on Cloudflare: a domain, a Worker, a database and AI per venture
With CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID, each venture gets its own
Worker (time-<slug>) with its own D1 database and Workers AI. The Worker serves
the venture's GitHub Pages folder under <slug>.<TIME_VENTURE_DOMAIN> (or
workers.dev) and adds a small API: share links stored in D1, and a
rate-limited small model. The page reaches it through time.js, which Time
writes next to index.html and the build may not edit; every call degrades to
null, so products still work on Pages alone and in the headless checks.

The backend is deployed when a venture is picked, so the plan, the signal
issue and the page all carry the venture's own domain. A Cloudflare failure
never holds a venture: it launches on Pages and the chores retry. The chores
also backfill older ventures and redeploy every venture when worker.js or its
settings change (a revision hash), a couple per tick; update.yml carries the
new files. The doctor checks the token. Offline tests cover the provisioner,
the loop with and without Cloudflare, the backfill and redeploys, and the
worker itself (node, against a fake D1, AI and Pages).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wyb3QQDESFkosKRXzrXqwr
2026-10-12 10:50:13 -07:00
teahubxyzandClaude Opus 5.5 32fa6ee49d venture: start a new venture whenever you like
The schedule starts one venture card a day, and Run workflow only
advanced the cards already open. Run workflow now has a "Start a new
venture now" checkbox (gh workflow run venture.yml -f start=true) that
opens a fresh card even when today's has run; a second card on the same
day is titled "Venture <day> (2)". The schedule is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UpT7eWzeLhRwuYmsSQnbRb
2026-10-11 21:18:11 -07:00
Claude f64a48300d Ventures: the product is the page
Taste test on the relaunched MDecks: the notplanned launch-page template
and its rotation of print styles turned the working tool into a section
under a big hero, and every page looked like the same magazine. Now:
- the brief puts the tool in the first screen under a slim header (name,
  a few words, the one signup button); how it works, why, pricing and
  limits sit quietly below;
- the look follows the product (a slide tool should feel like a slide
  tool), dark or light; the design rotation is gone;
- headless Chrome fails a page whose product starts below the top third
  of the first screen, at phone and laptop size;
- an earlier version can be kept on purpose (prior_note), so MDecks can
  be rebuilt from the first design people liked.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UpT7eWzeLhRwuYmsSQnbRb
2026-10-11 16:55:28 -07:00
Claude 0c569ca5c2 Docs: Venice-first setup, and the venture loop in the setup skill
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UpT7eWzeLhRwuYmsSQnbRb
2026-10-11 16:14:48 -07:00
Claude cdfe4c7199 Venture loop: launch products, not pages
Ported from the notplanned venture template:
- launch round: every board seat writes a launch plan (positioning, first
  users, pricing, channels, 7-day success and kill lines); one seat
  synthesizes them into LAUNCH.md with where each idea came from
- launch page brief: one primary call to action in the hero, the working
  product preloaded with a sample, why-this-exists with real star counts,
  pricing (free plus at most two honest early-access tiers), honest limits,
  a design direction that rotates and never repeats the last six
- signups through a GitHub issue form prefilled with venture and plan;
  each signup is thanked on its own issue
- checks: deterministic gates, then headless Chrome measuring at exactly
  390x844 and 1280x800 (horizontal scroll, button below the fold, JS
  errors); two fix rounds, then andon with needs-human and /time retry
- a contact-sheet screenshot of phone and desktop on the card
- 7-day decision on distinct people: v2 card, kill, or one more week then
  park; a next version counts only signups after its own launch
- scheduling: a card that is measuring never blocks the others; one new
  card a day; a tick runs light stages back to back and one worker run
- the studio index at /ventures/ is generated from ventures.json

Security: the worker's shell no longer sees tokens or keys, its checkout
keeps no token in .git/config, and workflows don't persist credentials.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UpT7eWzeLhRwuYmsSQnbRb
2026-10-11 15:48:21 -07:00
github-actions[bot] a4970e3e2b Add Status section linking to CHANGELOG.md (#10)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-10-11 21:22:31 +00:00
claude 439cf7d1cd Venture loop on GitHub: trending repos -> pitches -> board -> build -> Pages
venture.py runs one stage per tick on a `venture` card: scout (GitHub search,
repos with the most new stars this week), pitch (each seat proposes one static
page product), board (Borda over seat rankings), build (the Venice worker on
gh-pages), ship (GitHub Pages). TIME_VENTURE=on starts it; off by default.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UpT7eWzeLhRwuYmsSQnbRb
2026-10-11 14:05:41 -07:00
claude 750d9a9fad Venice seats can be the worker: TIME_WORKER=venice:<seat>
A seat gets hands through the repo's own Actions token: list/read/write files on
branch time/card-N via the contents API, run shell on a checkout, open the PR.
Same contract as the Cursor worker (PR body says Closes #N), so review, landing
and next-card are unchanged. Workflow files are refused to the seat. Needs only
VENICE_API_KEY; no Cursor key.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UpT7eWzeLhRwuYmsSQnbRb
2026-10-11 12:38:00 -07:00
claude 889e93799e Hands-off Time: spec planner, auto-merge on Approve + green checks, next card, update workflow
- spec issues (label spec) become queued cards, parsed deterministically, seat fallback
- TIME_AUTOMERGE=on: squash-merge when the latest trusted verdict is Approve and all checks pass
- Object, red or missing checks, or protected paths go to needs-human
- merged card frees the slot; the next unblocked queued card gets ready and dispatches in the same run
- update.yml pulls the engine from teahubxyz/time into project repos via PR
- ci.yml runs Time's own tests

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UpT7eWzeLhRwuYmsSQnbRb
2026-10-11 11:46:43 -07:00
teahubxyz 83bc5d4c60 readme: heartbeat fires on label 2026-10-10 20:03:34 -07:00
teahubxyz ca667b7f20 time: Cursor worker, doctor, skill (README.md) 2026-10-10 19:56:31 -07:00
teahubxyz 55488a12bc readme: hourly heartbeat 2026-10-10 19:35:01 -07:00
teahubxyz e7e4cdb43e time v0: README.md 2026-10-10 19:33:26 -07:00
teahubxyz 192e7b6d76 Initial commit 2026-10-10 19:25:37 -07:00