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
53 lines
2.1 KiB
YAML
53 lines
2.1 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
|
|
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: 5
|
|
steps:
|
|
- uses: actions/checkout@v5
|
|
with:
|
|
sparse-checkout: .github/time
|
|
- 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 }}
|