jonah-fleet 1.1.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/CHANGELOG.md +115 -0
  2. package/README.md +49 -6
  3. package/dist/commands/contribute.d.ts +29 -0
  4. package/dist/commands/contribute.d.ts.map +1 -0
  5. package/dist/commands/daemon.d.ts +8 -0
  6. package/dist/commands/daemon.d.ts.map +1 -0
  7. package/dist/commands/init.d.ts +13 -0
  8. package/dist/commands/init.d.ts.map +1 -0
  9. package/dist/commands/monitor.d.ts +16 -0
  10. package/dist/commands/monitor.d.ts.map +1 -0
  11. package/dist/commands/run.d.ts +11 -0
  12. package/dist/commands/run.d.ts.map +1 -0
  13. package/dist/commands/status.d.ts +9 -0
  14. package/dist/commands/status.d.ts.map +1 -0
  15. package/dist/commands/sync.d.ts +7 -0
  16. package/dist/commands/sync.d.ts.map +1 -0
  17. package/dist/commands/telemetry.d.ts +14 -0
  18. package/dist/commands/telemetry.d.ts.map +1 -0
  19. package/dist/index.d.ts +2 -2
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +1986 -211
  22. package/dist/lib/daemon.d.ts +34 -0
  23. package/dist/lib/daemon.d.ts.map +1 -0
  24. package/dist/lib/dashboard.d.ts +10 -0
  25. package/dist/lib/dashboard.d.ts.map +1 -0
  26. package/dist/lib/detector.d.ts +25 -0
  27. package/dist/lib/detector.d.ts.map +1 -0
  28. package/dist/lib/diff.d.ts +10 -0
  29. package/dist/lib/diff.d.ts.map +1 -0
  30. package/dist/lib/evals.d.ts +72 -0
  31. package/dist/lib/evals.d.ts.map +1 -0
  32. package/dist/lib/fleet-query.d.ts +102 -0
  33. package/dist/lib/fleet-query.d.ts.map +1 -0
  34. package/dist/lib/global-config.d.ts +10 -0
  35. package/dist/lib/global-config.d.ts.map +1 -0
  36. package/dist/lib/installer.d.ts +27 -0
  37. package/dist/lib/installer.d.ts.map +1 -0
  38. package/dist/lib/manifest.d.ts +6 -0
  39. package/dist/lib/manifest.d.ts.map +1 -0
  40. package/dist/lib/presets.d.ts +52 -0
  41. package/dist/lib/presets.d.ts.map +1 -0
  42. package/dist/lib/runner.d.ts +40 -0
  43. package/dist/lib/runner.d.ts.map +1 -0
  44. package/dist/lib/telemetry.d.ts +90 -0
  45. package/dist/lib/telemetry.d.ts.map +1 -0
  46. package/dist/lib/worktree.d.ts +34 -0
  47. package/dist/lib/worktree.d.ts.map +1 -0
  48. package/package.json +17 -5
  49. package/schema.json +44 -1
  50. package/templates/docs/AGENTS.template.md +15 -0
  51. package/templates/prompts/ORCHESTRATION.md +107 -7
  52. package/templates/prompts/analytics-review.md +91 -0
  53. package/templates/prompts/autowork.md +15 -4
  54. package/templates/prompts/issues-housekeeping.md +2 -1
  55. package/templates/prompts/optimizer.md +46 -8
  56. package/templates/prompts/peer-review.md +35 -11
  57. package/templates/prompts/product-planning.md +18 -7
  58. package/templates/skills/diagnosing-bugs/SKILL.md +9 -0
  59. package/templates/workflows/autowork-cron.yml +19 -1
  60. package/templates/workflows/prompt-optimizer-cron.yml +22 -0
  61. package/templates/workflows/trigger-autowork-manual.yml +169 -0
  62. package/templates/workflows/trigger-autowork-on-bug.yml +5 -5
  63. package/templates/workflows/trigger-autowork-on-merge.yml +3 -3
  64. package/templates/workflows/trigger-review-routine.yml +107 -11
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Objective
4
4
 
5
- Turn strategy and evidence into **well-scoped, ready-to-build work** and a **current roadmap** — the "plan" between analytics/measurement and autowork's build phase. Each run reads roadmap priorities, analytics signals, and user feedback to **propose** the next units of product work: new feature issues, formal specs/PRDs for larger epics, backlog re-ranking recommendations, and roadmap updates.
5
+ Turn strategy and evidence into **well-scoped, ready-to-build work** and a **current roadmap** — the "plan" between analytics/measurement and autowork's build phase. Each run reads roadmap priorities, closed measurement trackers (`RECOMMENDATION: [PIVOT | DEPRECATE | ITERATE]`), analytics signals, and user feedback to **propose** the next units of product work: new feature issues, feature pruning and deprecations, formal specs/PRDs for larger epics, backlog re-ranking recommendations, and roadmap updates.
6
6
 
7
7
  This routine runs behind a **human approval gate**: it **never files autowork-ready issues on its own**. It stages proposals in one planning issue for operator approval; only a subsequent operator-approved **Promote** run creates the real issues autowork can claim.
8
8
 
@@ -11,9 +11,10 @@ This routine runs behind a **human approval gate**: it **never files autowork-re
11
11
  This routine runs in two modes: **Propose** (scheduled cron sweep / unapproved fire) and **Promote** (operator-approved fire).
12
12
 
13
13
  In **Propose mode**, SUCCESS requires:
14
- - [ ] Read current roadmap, domain documentation, and recent feedback/analytics findings
14
+ - [ ] Read current roadmap, domain documentation, closed measurement trackers, and recent feedback/analytics findings
15
+ - [ ] Performed Feature Pruning & Deprecation Audit: evaluated shipped features and measurement outcomes for low-ROI (<2% user adoption or >50% failure rate) features, drafting deprecation, removal, or simplification proposals
15
16
  - [ ] Created or updated exactly one dated staging issue (`🗺️ Product Plan — {date}`) containing:
16
- - Up to 3 well-scoped proposals (Summary/Tasks/Why/Complexity)
17
+ - Up to 3 well-scoped proposals (Summary/Tasks/Why/Complexity), covering additions, pivots, or deprecations
17
18
  - Backlog re-ranking recommendations
18
19
  - Formal `/to-spec` PRD drafts for any proposal above `size/M`
19
20
  - Proposed `ROADMAP.md` updates
@@ -33,6 +34,13 @@ If any criterion cannot be met, stop immediately and log FAILURE with the reason
33
34
  - **Max iterations**: 30 — after 30 tool call rounds without completing Definition of Done, STOP. Log FAILURE with category `token_limit`.
34
35
  - **Max scope**: planning and staging only. Do not implement code or open feature PRs.
35
36
  - **Language Requirement**: All GitHub issue titles, descriptions, task checklists, and comments MUST be written in **English**.
37
+ - **Session link footer**: sign every GitHub post with the Antigravity run footer (`_Generated by [Antigravity](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID})_`).
38
+
39
+ ## Negative examples (DO NOT do these)
40
+
41
+ - Do not ignore closed measurement tracker directives (`RECOMMENDATION: [PIVOT | DEPRECATE | ITERATE]`) — incorporate them directly into planning.
42
+ - Do not propose only new features while ignoring dead features with <2% adoption or >50% failure rates — keep the codebase lean by actively proposing deprecations.
43
+ - Do not create unapproved autowork-ready candidate issues directly in Propose mode.
36
44
 
37
45
  ## Instructions
38
46
 
@@ -43,10 +51,13 @@ If any criterion cannot be met, stop immediately and log FAILURE with the reason
43
51
 
44
52
  ### Steps 1–3: Propose Mode (Staging Proposals)
45
53
 
46
- 1. Read `ROADMAP.md`, `AGENTS.md`, and open issues.
47
- 2. Draft up to 3 high-impact proposals based on roadmap priorities and user feedback.
48
- 3. For proposals sized `size/M` or above, draft a formal specification using `/to-spec`.
49
- 4. Stage all proposals in a dedicated staging issue: `🗺️ Product Plan — {YYYY-MM-DD}` assigned to the repo maintainer.
54
+ 1. Read `ROADMAP.md`, `AGENTS.md`, closed measurement trackers with `RECOMMENDATION: [PIVOT | DEPRECATE | ITERATE]`, and open issues.
55
+ 2. **Feature Pruning & Deprecation Audit**:
56
+ - Audit shipped features and closed measurement tracker verdicts.
57
+ - For any feature with <2% user adoption, sub-threshold CTR, or >50% failure rate, draft explicit deprecation, removal, or pivot proposals to keep the codebase lean and eliminate maintenance waste.
58
+ 3. Draft up to 3 high-impact proposals (including additions, pivots, or deprecations) based on roadmap priorities, measurement outcomes, and user feedback.
59
+ 4. For proposals sized `size/M` or above, draft a formal specification using `/to-spec`.
60
+ 5. Stage all proposals in a dedicated staging issue: `🗺️ Product Plan — {YYYY-MM-DD}` assigned to the repo maintainer.
50
61
 
51
62
  ### Step 4: Promote Mode (Approved Execution)
52
63
 
@@ -85,6 +85,15 @@ Done when **every remaining element is load-bearing**: removing any one of them
85
85
 
86
86
  Do not proceed until you have reproduced **and** minimised.
87
87
 
88
+ ## Intent vs. Defect Guardrail (Telemetry Rabbit Hole Prevention)
89
+
90
+ When diagnosing an under-performing event, low-conversion funnel, or zero-click CTA:
91
+
92
+ 1. **Check for mechanical functionality first.** Run the code path or click handler in isolation: does it execute, route, and emit telemetry without throwing?
93
+ 2. **Distinguish user intent from code defects.** If the feature renders above the fold and works when clicked, but telemetry reveals near-zero clicks (<2% adoption), the root cause is **lack of user intent**, not a software bug.
94
+ 3. **Prevent the Telemetry Rabbit Hole.** Do NOT spend cycles instrumenting elaborate fallback telemetry, defensive error handling, or retry loops for a feature users simply do not want.
95
+ 4. **Handoff to product planning.** Reclassify the issue as a product/UX question (`needs-design` or `roadmap/*`) and hand it off to `product-planning` rather than writing code fixes.
96
+
88
97
  ## Phase 3: Hypothesise
89
98
 
90
99
  Generate **3–5 ranked hypotheses** before testing any of them. Single-hypothesis generation anchors on the first plausible idea.
@@ -12,6 +12,10 @@ on:
12
12
  description: 'Optional issue number to work in Targeted mode (leave blank for Scan mode)'
13
13
  required: false
14
14
  type: string
15
+ issue_number:
16
+ description: 'Alias for target_issue (e.g. 18)'
17
+ required: false
18
+ type: string
15
19
 
16
20
  concurrency:
17
21
  group: autowork-agent-scan
@@ -106,7 +110,7 @@ jobs:
106
110
  GOOGLE_API_KEY: ${{ secrets.GEMINI_API_KEY }}
107
111
  ANTIGRAVITY_API_KEY: ${{ secrets.GEMINI_API_KEY }}
108
112
  GH_TOKEN: ${{ secrets.GH_PAT || github.token }}
109
- TARGET_ISSUE: ${{ inputs.target_issue }}
113
+ TARGET_ISSUE: ${{ inputs.target_issue || inputs.issue_number }}
110
114
  SKILLS_PROMPT: ${{ steps.skills.outputs.skills_prompt }}
111
115
  GITHUB_SERVER_URL: ${{ github.server_url }}
112
116
  GITHUB_REPOSITORY: ${{ github.repository }}
@@ -132,6 +136,20 @@ jobs:
132
136
  cat "$LATEST_LOG" >> "$GITHUB_STEP_SUMMARY"
133
137
  fi
134
138
 
139
+ - name: Emit Fleet Telemetry (Opt-in)
140
+ if: always()
141
+ env:
142
+ GH_TOKEN: ${{ secrets.GH_PAT || github.token }}
143
+ TELEMETRY_ENDPOINT: ${{ secrets.JONAH_FLEET_TELEMETRY_ENDPOINT }}
144
+ GITHUB_REPOSITORY: ${{ github.repository }}
145
+ GITHUB_RUN_ID: ${{ github.run_id }}
146
+ GITHUB_RUN_NUMBER: ${{ github.run_number }}
147
+ run: |
148
+ LATEST_LOG=$(ls -t .github/prompts/logs/autowork/*.md 2>/dev/null | head -n 1)
149
+ if [ -n "$LATEST_LOG" ] && [ -f "$LATEST_LOG" ]; then
150
+ npx --yes jonah-fleet telemetry --emit --log "$LATEST_LOG" --endpoint "$TELEMETRY_ENDPOINT" || true
151
+ fi
152
+
135
153
  - name: Verify Atomic Handoff Invariant (PR Existence Guard)
136
154
  if: always()
137
155
  env:
@@ -83,3 +83,25 @@ jobs:
83
83
  --output-format text \
84
84
  --print-timeout 35m \
85
85
  --dangerously-skip-permissions
86
+
87
+ - name: Emit run summary
88
+ if: always()
89
+ run: |
90
+ LATEST_LOG=$(ls -t .github/prompts/logs/optimizer/*.md 2>/dev/null | head -n 1)
91
+ if [ -n "$LATEST_LOG" ] && [ -n "$GITHUB_STEP_SUMMARY" ]; then
92
+ cat "$LATEST_LOG" >> "$GITHUB_STEP_SUMMARY"
93
+ fi
94
+
95
+ - name: Emit Fleet Telemetry (Opt-in)
96
+ if: always()
97
+ env:
98
+ GH_TOKEN: ${{ secrets.GH_PAT || github.token }}
99
+ TELEMETRY_ENDPOINT: ${{ secrets.JONAH_FLEET_TELEMETRY_ENDPOINT }}
100
+ GITHUB_REPOSITORY: ${{ github.repository }}
101
+ GITHUB_RUN_ID: ${{ github.run_id }}
102
+ GITHUB_RUN_NUMBER: ${{ github.run_number }}
103
+ run: |
104
+ LATEST_LOG=$(ls -t .github/prompts/logs/optimizer/*.md 2>/dev/null | head -n 1)
105
+ if [ -n "$LATEST_LOG" ] && [ -f "$LATEST_LOG" ]; then
106
+ npx --yes jonah-fleet telemetry --emit --log "$LATEST_LOG" --endpoint "$TELEMETRY_ENDPOINT" || true
107
+ fi
@@ -0,0 +1,169 @@
1
+ name: Trigger Autowork Manually (Targeted)
2
+
3
+ # Manual execution of the Autowork routine on a specific issue via workflow_dispatch or badge link click.
4
+
5
+ on:
6
+ workflow_dispatch:
7
+ inputs:
8
+ issue_number:
9
+ description: 'Target issue number to work in Targeted mode (e.g. 18)'
10
+ required: true
11
+ type: string
12
+ mode:
13
+ description: 'Execution mode (targeted or scan)'
14
+ required: false
15
+ default: 'targeted'
16
+ type: choice
17
+ options:
18
+ - targeted
19
+ - scan
20
+ custom_prompt:
21
+ description: 'Optional custom instructions or overrides'
22
+ required: false
23
+ type: string
24
+
25
+ concurrency:
26
+ group: autowork-manual-${{ inputs.issue_number || github.run_id }}
27
+ cancel-in-progress: false
28
+
29
+ jobs:
30
+ run-autowork:
31
+ runs-on: ubuntu-latest
32
+ timeout-minutes: 65
33
+ permissions:
34
+ contents: write
35
+ issues: write
36
+ pull-requests: write
37
+ statuses: write
38
+ actions: read
39
+ steps:
40
+ - name: Checkout repository
41
+ uses: actions/checkout@v4
42
+ with:
43
+ fetch-depth: 0
44
+
45
+ - name: Setup Node.js
46
+ uses: actions/setup-node@v4
47
+ with:
48
+ node-version: 22
49
+
50
+ - name: Configure Git author identity
51
+ run: |
52
+ git config --global user.name "github-actions[bot]"
53
+ git config --global user.email "github-actions[bot]@users.noreply.github.com"
54
+ git config --global --add safe.directory "$GITHUB_WORKSPACE"
55
+
56
+ - name: Cache Antigravity CLI
57
+ id: cache-agy
58
+ uses: actions/cache@v4
59
+ with:
60
+ path: ~/.local/bin/agy
61
+ key: agy-cli-linux-amd64-v1
62
+
63
+ - name: Install Antigravity CLI
64
+ if: steps.cache-agy.outputs.cache-hit != 'true'
65
+ run: |
66
+ curl -fsSL https://antigravity.google/cli/install.sh | bash
67
+
68
+ - name: Add Antigravity CLI to PATH
69
+ run: echo "$HOME/.local/bin" >> $GITHUB_PATH
70
+
71
+ - name: Write Antigravity OAuth Token
72
+ env:
73
+ ANTIGRAVITY_OAUTH_TOKEN: ${{ secrets.ANTIGRAVITY_OAUTH_TOKEN || secrets.GEMINI_API_KEY }}
74
+ run: |
75
+ if [ -z "$ANTIGRAVITY_OAUTH_TOKEN" ]; then
76
+ echo "::error::Neither ANTIGRAVITY_OAUTH_TOKEN nor GEMINI_API_KEY secret is set; cannot authenticate Antigravity CLI." >&2
77
+ exit 1
78
+ fi
79
+ mkdir -p "$HOME/.gemini/antigravity-cli"
80
+ chmod 700 "$HOME/.gemini/antigravity-cli"
81
+ printf '%s' "$ANTIGRAVITY_OAUTH_TOKEN" > "$HOME/.gemini/antigravity-cli/antigravity-oauth-token"
82
+ chmod 600 "$HOME/.gemini/antigravity-cli/antigravity-oauth-token"
83
+
84
+ - name: Preflight validation
85
+ env:
86
+ GH_TOKEN: ${{ github.token }}
87
+ run: |
88
+ if [ ! -s "$HOME/.gemini/antigravity-cli/antigravity-oauth-token" ]; then
89
+ echo "::error::Preflight check failed: Antigravity OAuth token file is missing or empty." >&2
90
+ exit 1
91
+ fi
92
+ if ! gh auth status >/dev/null 2>&1; then
93
+ echo "::error::GitHub CLI authentication check failed with GITHUB_TOKEN." >&2
94
+ exit 1
95
+ fi
96
+ echo "✓ Preflight credential and GitHub CLI validation passed."
97
+
98
+ - name: Discover domain skills
99
+ id: skills
100
+ run: |
101
+ SKILLS_PROMPT=""
102
+ if [ -d ".agents/skills" ]; then
103
+ for skill_path in .agents/skills/*/SKILL.md; do
104
+ if [ -f "$skill_path" ]; then
105
+ SKILLS_PROMPT="${SKILLS_PROMPT}Read and follow ${skill_path}. "
106
+ fi
107
+ done
108
+ fi
109
+ echo "skills_prompt=$SKILLS_PROMPT" >> "$GITHUB_OUTPUT"
110
+
111
+ - name: Run Autowork
112
+ timeout-minutes: 60
113
+ env:
114
+ GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
115
+ GOOGLE_API_KEY: ${{ secrets.GEMINI_API_KEY }}
116
+ ANTIGRAVITY_API_KEY: ${{ secrets.GEMINI_API_KEY }}
117
+ GH_TOKEN: ${{ secrets.GH_PAT || github.token }}
118
+ TARGET_ISSUE: ${{ inputs.issue_number }}
119
+ MODE: ${{ inputs.mode || 'targeted' }}
120
+ CUSTOM_PROMPT: ${{ inputs.custom_prompt }}
121
+ SKILLS_PROMPT: ${{ steps.skills.outputs.skills_prompt }}
122
+ GITHUB_SERVER_URL: ${{ github.server_url }}
123
+ GITHUB_REPOSITORY: ${{ github.repository }}
124
+ GITHUB_RUN_ID: ${{ github.run_id }}
125
+ run: |
126
+ if [ -n "$TARGET_ISSUE" ] && [ "$MODE" != "scan" ]; then
127
+ PROMPT="You are the Autowork routine for this repository. Read and follow the instructions in .github/prompts/autowork.md exactly. ${SKILLS_PROMPT} Your target is issue #${TARGET_ISSUE}. You are in Targeted mode: work issue #${TARGET_ISSUE} directly, ahead of Phase 1 convergence and priority scan."
128
+ else
129
+ PROMPT="You are the Autowork routine for this repository. Read and follow the instructions in .github/prompts/autowork.md exactly. ${SKILLS_PROMPT} You are in Scan mode: check open PRs for review comments to fix, close merged issues, then pick the highest-priority unclaimed issue."
130
+ fi
131
+
132
+ if [ -n "$CUSTOM_PROMPT" ]; then
133
+ PROMPT="${PROMPT} Additional instructions: ${CUSTOM_PROMPT}"
134
+ fi
135
+
136
+ agy -p "$PROMPT" \
137
+ --model gemini-3.7-flash-high \
138
+ --output-format text \
139
+ --print-timeout 60m \
140
+ --dangerously-skip-permissions
141
+
142
+ - name: Emit run summary
143
+ if: always()
144
+ run: |
145
+ LATEST_LOG=$(ls -t .github/prompts/logs/autowork/*.md 2>/dev/null | head -n 1)
146
+ if [ -n "$LATEST_LOG" ] && [ -n "$GITHUB_STEP_SUMMARY" ]; then
147
+ cat "$LATEST_LOG" >> "$GITHUB_STEP_SUMMARY"
148
+ fi
149
+
150
+ - name: Verify Atomic Handoff Invariant (PR Existence Guard)
151
+ if: always()
152
+ env:
153
+ GH_TOKEN: ${{ github.token }}
154
+ run: |
155
+ LATEST_LOG=$(ls -t .github/prompts/logs/autowork/*.md 2>/dev/null | head -n 1)
156
+ if [ -n "$LATEST_LOG" ]; then
157
+ if grep -q "Result.*SUCCESS" "$LATEST_LOG"; then
158
+ WORKED_BRANCH=$(grep -E '^\s*-\s*(Pushed branch|Branch):' "$LATEST_LOG" | head -n 1 | sed -E 's/.*`([^`]+)`.*/\1/')
159
+ if [ -n "$WORKED_BRANCH" ] && [[ "$WORKED_BRANCH" =~ (feat|fix)/ ]]; then
160
+ echo "Verifying PR existence for branch: $WORKED_BRANCH"
161
+ PR_COUNT=$(gh pr list --head "$WORKED_BRANCH" --state all --json number --jq 'length' 2>/dev/null || echo "0")
162
+ if [ "$PR_COUNT" -eq 0 ]; then
163
+ echo "::error::Atomic Handoff Invariant Violated: Branch '$WORKED_BRANCH' was implemented and pushed, but no pull request exists on GitHub!" >&2
164
+ exit 1
165
+ fi
166
+ echo "✓ Verified pull request exists on GitHub for branch: $WORKED_BRANCH"
167
+ fi
168
+ fi
169
+ fi
@@ -11,10 +11,10 @@ concurrency:
11
11
  jobs:
12
12
  fire-autowork:
13
13
  if: >-
14
- (github.event.action == 'opened' && contains(github.event.issue.labels.*.name, 'bug') && contains(github.event.issue.labels.*.name, 'priority/P1')) ||
15
- (github.event.action == 'labeled' && (github.event.label.name == 'bug' || github.event.label.name == 'priority/P1'))
14
+ (github.event.action == 'opened' && contains(github.event.issue.labels.*.name, 'bug') && (contains(github.event.issue.labels.*.name, 'priority/P1') || contains(github.event.issue.labels.*.name, 'priority/P0'))) ||
15
+ (github.event.action == 'labeled' && contains(github.event.issue.labels.*.name, 'bug') && (contains(github.event.issue.labels.*.name, 'priority/P1') || contains(github.event.issue.labels.*.name, 'priority/P0')))
16
16
  runs-on: ubuntu-latest
17
- timeout-minutes: 65
17
+ timeout-minutes: 35
18
18
  permissions:
19
19
  contents: write
20
20
  issues: write
@@ -80,7 +80,7 @@ jobs:
80
80
  echo "skills_prompt=$SKILLS_PROMPT" >> "$GITHUB_OUTPUT"
81
81
 
82
82
  - name: Run Autowork
83
- timeout-minutes: 60
83
+ timeout-minutes: 30
84
84
  env:
85
85
  GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
86
86
  GOOGLE_API_KEY: ${{ secrets.GEMINI_API_KEY }}
@@ -97,5 +97,5 @@ jobs:
97
97
  agy -p "$PROMPT" \
98
98
  --model gemini-3.7-flash-high \
99
99
  --output-format text \
100
- --print-timeout 60m \
100
+ --print-timeout 30m \
101
101
  --dangerously-skip-permissions
@@ -15,7 +15,7 @@ jobs:
15
15
  github.event.pull_request.base.ref == 'main' &&
16
16
  github.event.pull_request.head.repo.full_name == github.repository
17
17
  runs-on: ubuntu-latest
18
- timeout-minutes: 65
18
+ timeout-minutes: 35
19
19
  permissions:
20
20
  contents: write
21
21
  issues: write
@@ -110,7 +110,7 @@ jobs:
110
110
 
111
111
  - name: Run Autowork
112
112
  if: steps.pick.outputs.skip != 'true'
113
- timeout-minutes: 60
113
+ timeout-minutes: 30
114
114
  env:
115
115
  GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
116
116
  GOOGLE_API_KEY: ${{ secrets.GEMINI_API_KEY }}
@@ -126,5 +126,5 @@ jobs:
126
126
  agy -p "$PROMPT" \
127
127
  --model gemini-3.7-flash-high \
128
128
  --output-format text \
129
- --print-timeout 60m \
129
+ --print-timeout 30m \
130
130
  --dangerously-skip-permissions
@@ -2,21 +2,48 @@ name: Trigger Review Routine
2
2
 
3
3
  on:
4
4
  pull_request:
5
- types: [ready_for_review, opened, reopened, synchronize]
5
+ types: [ready_for_review, opened, reopened, synchronize, review_requested]
6
6
  paths-ignore:
7
7
  - '.github/prompts/logs/**'
8
+ schedule:
9
+ # Periodic scan sweep every 2 hours to catch and recover any orphaned or unreviewed ready PRs
10
+ - cron: '45 */2 * * *'
11
+ workflow_dispatch:
12
+ inputs:
13
+ pr_number:
14
+ description: 'Optional PR number to review in Targeted mode (leave blank for Scan mode)'
15
+ required: false
16
+ type: string
17
+ issue_comment:
18
+ types: [created]
8
19
 
9
20
  concurrency:
10
- group: review-routine-pr-${{ github.event.pull_request.number }}
21
+ group: review-routine-pr-${{ github.event.pull_request.number || github.event.issue.number || inputs.pr_number || 'scan' }}
11
22
  cancel-in-progress: true
12
23
 
13
24
  jobs:
14
25
  trigger-routine:
15
26
  if: >-
16
- github.event.pull_request.draft == false &&
17
- github.event.pull_request.head.repo.full_name == github.repository
27
+ (github.event_name == 'pull_request' &&
28
+ github.event.pull_request.draft == false &&
29
+ github.event.pull_request.head.repo.full_name == github.repository &&
30
+ !startsWith(github.event.pull_request.head.ref, 'release-please--')) ||
31
+ (github.event_name == 'schedule') ||
32
+ (github.event_name == 'workflow_dispatch') ||
33
+ (github.event_name == 'issue_comment' &&
34
+ github.event.issue.pull_request != null &&
35
+ !endsWith(github.event.comment.user.login, '[bot]') &&
36
+ github.event.comment.user.type != 'Bot' &&
37
+ (startsWith(github.event.comment.body, '/review') ||
38
+ startsWith(github.event.comment.body, '/peer-review') ||
39
+ startsWith(github.event.comment.body, '/retrigger') ||
40
+ startsWith(github.event.comment.body, '/re-review') ||
41
+ contains(github.event.comment.body, '/review') ||
42
+ contains(github.event.comment.body, '/peer-review') ||
43
+ contains(github.event.comment.body, '/retrigger') ||
44
+ contains(github.event.comment.body, '/re-review')))
18
45
  runs-on: ubuntu-latest
19
- timeout-minutes: 60
46
+ timeout-minutes: 35
20
47
  permissions:
21
48
  contents: write
22
49
  actions: read
@@ -28,7 +55,21 @@ jobs:
28
55
  id: guard
29
56
  env:
30
57
  GH_TOKEN: ${{ github.token }}
58
+ PR_NUM: ${{ github.event.pull_request.number || github.event.issue.number || inputs.pr_number }}
31
59
  run: |
60
+ if [ -z "$PR_NUM" ]; then
61
+ if [ "${{ github.event_name }}" = "schedule" ]; then
62
+ open_prs=$(gh api "repos/${{ github.repository }}/pulls?state=open&per_page=1" --jq 'length' 2>/dev/null || echo "0")
63
+ if [ "$open_prs" -eq "0" ]; then
64
+ echo "No open PRs found in ${{ github.repository }} — skipping scheduled review routine scan."
65
+ echo "skip=true" >> "$GITHUB_OUTPUT"
66
+ exit 0
67
+ fi
68
+ fi
69
+ echo "skip=false" >> "$GITHUB_OUTPUT"
70
+ exit 0
71
+ fi
72
+
32
73
  gh_api_retry() {
33
74
  local endpoint="$1"
34
75
  shift
@@ -46,18 +87,37 @@ jobs:
46
87
  return 1
47
88
  }
48
89
 
49
- if ! pr=$(gh_api_retry "repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}"); then
90
+ if ! pr=$(gh_api_retry "repos/${{ github.repository }}/pulls/${PR_NUM}"); then
50
91
  echo "skip=false" >> "$GITHUB_OUTPUT"
51
92
  exit 0
52
93
  fi
53
94
 
54
95
  state=$(echo "$pr" | jq -r '.state')
55
96
  merged=$(echo "$pr" | jq -r '.merged')
97
+ head_ref=$(echo "$pr" | jq -r '.head.ref')
56
98
  if [ "$state" = "closed" ] || [ "$merged" = "true" ]; then
57
99
  echo "PR is already $state/merged=$merged — skipping review."
58
100
  echo "skip=true" >> "$GITHUB_OUTPUT"
59
101
  exit 0
60
102
  fi
103
+ if [[ "$head_ref" == release-please--* ]]; then
104
+ echo "PR head branch $head_ref is an automated release PR — skipping review."
105
+ echo "skip=true" >> "$GITHUB_OUTPUT"
106
+ exit 0
107
+ fi
108
+
109
+ # Priority-driven dual execution filter on direct pull_request triggers:
110
+ # If PR is labeled priority/P2 or priority/P3, skip immediate cloud review to let local agent daemons review it
111
+ # (cloud scheduled watchdog sweep will catch up if unreviewed > 48h).
112
+ if [ "${{ github.event_name }}" = "pull_request" ]; then
113
+ labels=$(echo "$pr" | jq -r '.labels[].name' 2>/dev/null || echo "")
114
+ if echo "$labels" | grep -qE '^priority/P[23]$'; then
115
+ echo "PR is labeled as lower priority (P2/P3) — skipping immediate cloud review for local peer-review daemon."
116
+ echo "skip=true" >> "$GITHUB_OUTPUT"
117
+ exit 0
118
+ fi
119
+ fi
120
+
61
121
  echo "skip=false" >> "$GITHUB_OUTPUT"
62
122
 
63
123
  - name: Checkout repository
@@ -112,26 +172,48 @@ jobs:
112
172
 
113
173
  - name: Run Peer Review
114
174
  if: steps.guard.outputs.skip != 'true'
115
- timeout-minutes: 55
175
+ timeout-minutes: 30
116
176
  env:
117
177
  GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
118
178
  GOOGLE_API_KEY: ${{ secrets.GEMINI_API_KEY }}
119
179
  ANTIGRAVITY_API_KEY: ${{ secrets.GEMINI_API_KEY }}
120
180
  GH_TOKEN: ${{ secrets.GH_PAT || github.token }}
121
- PR_NUMBER: ${{ github.event.pull_request.number }}
122
- PR_URL: ${{ github.event.pull_request.html_url }}
181
+ PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number || inputs.pr_number }}
182
+ PR_URL: ${{ github.event.pull_request.html_url || github.event.issue.html_url }}
123
183
  GITHUB_SERVER_URL: ${{ github.server_url }}
124
184
  GITHUB_REPOSITORY: ${{ github.repository }}
125
185
  GITHUB_RUN_ID: ${{ github.run_id }}
126
186
  run: |
127
- PROMPT="You are the Peer Review routine for this repository. Read and follow the instructions in .github/prompts/peer-review.md exactly. Your target is pull request #${PR_NUMBER} (${PR_URL}). You are in Targeted mode: review PR #${PR_NUMBER} directly."
187
+ if [ -n "$PR_NUMBER" ]; then
188
+ if [ -z "$PR_URL" ] || [[ "$PR_URL" == *"/issues/"* ]]; then
189
+ PR_URL="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/pull/${PR_NUMBER}"
190
+ fi
191
+ PROMPT="You are the Peer Review routine for this repository. Read and follow the instructions in .github/prompts/peer-review.md exactly. Your target is pull request #${PR_NUMBER} (${PR_URL}). You are in Targeted mode: review PR #${PR_NUMBER} directly."
192
+ else
193
+ PROMPT="You are the Peer Review routine for this repository. Read and follow the instructions in .github/prompts/peer-review.md exactly. You are in Scan mode: check open PRs and select the highest-priority PR to review."
194
+ fi
128
195
 
129
196
  agy -p "$PROMPT" \
130
197
  --model gemini-3.7-flash-high \
131
198
  --output-format text \
132
- --print-timeout 55m \
199
+ --print-timeout 30m \
133
200
  --dangerously-skip-permissions
134
201
 
202
+ - name: Handle Review Failure & PR Notification
203
+ if: failure() && steps.guard.outputs.skip != 'true'
204
+ env:
205
+ GH_TOKEN: ${{ secrets.GH_PAT || github.token }}
206
+ PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number || inputs.pr_number }}
207
+ GITHUB_SERVER_URL: ${{ github.server_url }}
208
+ GITHUB_REPOSITORY: ${{ github.repository }}
209
+ GITHUB_RUN_ID: ${{ github.run_id }}
210
+ run: |
211
+ if [ -n "$PR_NUMBER" ]; then
212
+ gh pr comment "$PR_NUMBER" --body "⚠️ **Peer Review Routine Notice**: The automated review session encountered an execution error (e.g., API rate/quota limit or runner interruption). The review will be retried automatically on the next scheduled scan sweep or can be re-triggered immediately by commenting \`/review\` on this PR.
213
+
214
+ _Generated by [Antigravity](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID})_" || true
215
+ fi
216
+
135
217
  - name: Emit run summary
136
218
  if: always() && steps.guard.outputs.skip != 'true'
137
219
  run: |
@@ -139,3 +221,17 @@ jobs:
139
221
  if [ -n "$LATEST_LOG" ] && [ -n "$GITHUB_STEP_SUMMARY" ]; then
140
222
  cat "$LATEST_LOG" >> "$GITHUB_STEP_SUMMARY"
141
223
  fi
224
+
225
+ - name: Emit Fleet Telemetry (Opt-in)
226
+ if: always() && steps.guard.outputs.skip != 'true'
227
+ env:
228
+ GH_TOKEN: ${{ secrets.GH_PAT || github.token }}
229
+ TELEMETRY_ENDPOINT: ${{ secrets.JONAH_FLEET_TELEMETRY_ENDPOINT }}
230
+ GITHUB_REPOSITORY: ${{ github.repository }}
231
+ GITHUB_RUN_ID: ${{ github.run_id }}
232
+ GITHUB_RUN_NUMBER: ${{ github.run_number }}
233
+ run: |
234
+ LATEST_LOG=$(ls -t .github/prompts/logs/peer-review/*.md 2>/dev/null | head -n 1)
235
+ if [ -n "$LATEST_LOG" ] && [ -f "$LATEST_LOG" ]; then
236
+ npx --yes jonah-fleet telemetry --emit --log "$LATEST_LOG" --endpoint "$TELEMETRY_ENDPOINT" || true
237
+ fi