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
56 lines
2.3 KiB
YAML
56 lines
2.3 KiB
YAML
name: heartbeat
|
|
# Time's clock: hourly, right away when a card gets `ready` or a spec gets `spec`, and when a PR is reviewed
|
|
# (dry-run until TIME_MODE=live; merges only with TIME_AUTOMERGE=on).
|
|
on:
|
|
schedule:
|
|
- cron: "7 * * * *"
|
|
workflow_dispatch:
|
|
issues:
|
|
types: [labeled]
|
|
pull_request_review:
|
|
types: [submitted]
|
|
issue_comment:
|
|
types: [created]
|
|
permissions:
|
|
contents: write # squash-merge approved, green PRs
|
|
issues: write
|
|
pull-requests: write
|
|
checks: read
|
|
statuses: write # a Venice worker's test run is recorded as the PR's check
|
|
concurrency:
|
|
group: heartbeat
|
|
cancel-in-progress: false
|
|
jobs:
|
|
tick:
|
|
# issues: only `ready`/`spec` labels. comments: only on PRs, only a reviewer verdict (Approve/Object).
|
|
if: >-
|
|
(github.event_name != 'issues' || contains(fromJSON('["ready","spec"]'), github.event.label.name)) &&
|
|
(github.event_name != 'issue_comment' || (github.event.issue.pull_request &&
|
|
(startsWith(github.event.comment.body, '**Approve') || startsWith(github.event.comment.body, 'Approve') ||
|
|
startsWith(github.event.comment.body, '**Object') || startsWith(github.event.comment.body, 'Object'))))
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 20
|
|
steps:
|
|
- uses: actions/checkout@v5
|
|
with:
|
|
sparse-checkout: .github/time
|
|
persist-credentials: false # the worker's shell must not find the token in .git/config
|
|
- run: python3 .github/time/time.py heartbeat
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
CURSOR_API_KEY: ${{ secrets.CURSOR_API_KEY }}
|
|
VENICE_API_KEY: ${{ secrets.VENICE_API_KEY }}
|
|
TIME_MODE: ${{ vars.TIME_MODE }}
|
|
TIME_DAILY_CAP: ${{ vars.TIME_DAILY_CAP }}
|
|
TIME_CURSOR_MODEL: ${{ vars.TIME_CURSOR_MODEL }}
|
|
TIME_REVIEW: ${{ vars.TIME_REVIEW }}
|
|
TIME_STUCK_HOURS: ${{ vars.TIME_STUCK_HOURS }}
|
|
TIME_AUTOMERGE: ${{ vars.TIME_AUTOMERGE }}
|
|
TIME_REQUIRE_CHECKS: ${{ vars.TIME_REQUIRE_CHECKS }}
|
|
TIME_PROTECTED: ${{ vars.TIME_PROTECTED }}
|
|
TIME_PARALLEL: ${{ vars.TIME_PARALLEL }}
|
|
TIME_PLANNER: ${{ vars.TIME_PLANNER }}
|
|
TIME_WORKER: ${{ vars.TIME_WORKER }}
|
|
TIME_WORKER_STEPS: ${{ vars.TIME_WORKER_STEPS }}
|
|
TIME_WORKER_MAX_TOKENS: ${{ vars.TIME_WORKER_MAX_TOKENS }}
|