Merge pull request #2453 from PR0M3TH3AN/claude/add-pr-checking-ZTrrq

Replace gh CLI with curl for GitHub API queries in agent workflows
This commit is contained in:
thePR0M3TH3AN authored and GitHub committed 2026-02-13 11:17:39 -05:00
commit 6aa9da1383
11 files changed
+97 -103

No files matched your search

+16 -21
View File
@@ -204,7 +204,11 @@ This project uses multiple AI agents (Claude Code, OpenAI Codex, Google Jules) w
### Before Starting Work
1. **Check open PRs.** Run `gh pr list --state open` or check GitHub. If another agent already has a PR touching the same files or subsystem, do not create a competing PR. Instead, note the conflict and ask the maintainer how to proceed.
1. **Check open PRs.** Run the following command to list all open PRs:
```
curl -s "https://api.github.com/repos/PR0M3TH3AN/bitvid/pulls?state=open&per_page=100" | jq '{count: length, titles: [.[].title]}'
```
If another agent already has a PR touching the same files or subsystem, do not create a competing PR. Instead, note the conflict and ask the maintainer how to proceed.
2. **Check this section for in-flight work.** The maintainer may list active work areas below. Respect these reservations.
3. **Read KNOWN_ISSUES.md.** Do not open PRs to fix issues already documented there unless explicitly asked.
@@ -242,37 +246,28 @@ When you create a PR or start work, leave a clear signal:
### Task Claiming Protocol (Draft PR Lock)
To prevent multiple agents from working on the same task simultaneously, every agent must **check for and create a draft PR** before starting work. The draft PR acts as a distributed lock visible to all agents across all platforms (Claude Code, Codex, Jules).
To prevent multiple agents from working on the same task simultaneously, every agent must **check open PRs and create a claim** before starting work. The claim (pushed branch + `started` log file) acts as a distributed lock visible to all agents across all platforms (Claude Code, Codex, Jules).
**Before starting any task:**
1. **Check for existing claims.** Search for open or draft PRs matching the task:
1. **Check for existing claims.** Search for open PRs matching the task:
```
gh pr list --state open --search "<agent-name-or-task-identifier>"
curl -s "https://api.github.com/repos/PR0M3TH3AN/bitvid/pulls?state=open&per_page=100" | jq '{count: length, titles: [.[].title]}'
```
If a matching PR exists (open or draft), **skip the task** — another agent is already working on it.
If a matching PR exists (open or draft) for the same agent or subsystem, **skip the task** — another agent is already working on it.
2. **Claim the task.** If no matching PR exists:
a. Create your working branch.
b. Make a minimal initial commit (e.g., update `CONTEXT.md` with the task scope).
c. Push the branch and immediately open a **draft PR**:
```
gh pr create --draft \
--title "[<zone>] <agent-name>: <brief description>" \
--body "Claimed by <agent-name> at <timestamp>. Work in progress."
```
d. Only after the draft PR is successfully created, begin the actual work.
b. Make a minimal initial commit (e.g., create a `context/CONTEXT_<timestamp>.md` with the task scope).
c. Create a `started` log file in the appropriate task-log directory.
d. Push the branch immediately to make the claim visible.
e. Only after the branch is pushed and the claim is visible, begin the actual work.
3. **Handle race conditions.** After creating your draft PR, re-check for duplicates:
3. **Handle race conditions.** After pushing your claim, re-check for duplicates:
```
gh pr list --state open --search "<agent-name-or-task-identifier>"
```
If you find another agent's PR for the same task that was created **before** yours, close your PR with `gh pr close <your-pr-number>` and skip the task.
4. **Convert to ready when done.** When the task is complete and verified, mark the draft PR as ready for review:
```
gh pr ready
curl -s "https://api.github.com/repos/PR0M3TH3AN/bitvid/pulls?state=open&per_page=100" | jq '{count: length, titles: [.[].title]}'
```
If you find another agent's PR for the same task that was created **before** yours, abandon your branch and skip the task.
**Scheduler agents:** Daily and weekly scheduler agents must follow this protocol in addition to their directory-based rotation logic (`docs/agents/task-logs/daily/` and `docs/agents/task-logs/weekly/`). The draft PR check happens _after_ determining the next task but _before_ executing it. See the scheduler prompts for the specific implementation steps.
+5 -1
View File
@@ -458,7 +458,11 @@ This project uses multiple AI coding agents working in parallel:
All agents **must** follow the subsystem boundaries and PR discipline rules in `AGENTS.md` Section 12. The key principles:
1. **Check before you start.** Look at open PRs (`gh pr list`) before beginning work. If another agent has an open PR touching the same files, stop and flag the conflict.
1. **Check before you start.** Look at open PRs before beginning work by running:
```
curl -s "https://api.github.com/repos/PR0M3TH3AN/bitvid/pulls?state=open&per_page=100" | jq '{count: length, titles: [.[].title]}'
```
If another agent has an open PR touching the same files, stop and flag the conflict.
2. **One subsystem per PR.** Don't mix unrelated changes. A lint fix and a feature addition are two separate PRs.
3. **`js/app.js` is single-writer.** Only one PR at a time should modify the main orchestrator.
4. **Merge fast, branch short.** Long-lived branches cause exponential merge pain with multiple agents. Keep PRs small and mergeable in one sitting.
+4 -6
View File
@@ -14,10 +14,9 @@ before choosing a task — is to run these two commands. Not later. NOW.
COMMAND 1 — Check for open daily agent PRs:
gh pr list --repo PR0M3TH3AN/bitvid --state open --json number,title,createdAt,author --limit 100 | grep -i "\[daily\]"
curl -s "https://api.github.com/repos/PR0M3TH3AN/bitvid/pulls?state=open&per_page=100" | jq '{count: length, titles: [.[].title]}'
If `gh` is not available, use this fallback:
curl -s "https://api.github.com/repos/PR0M3TH3AN/bitvid/pulls?state=open&per_page=100" | grep -o '"title":"[^"]*\[daily\][^"]*"'
Review the output. Any title containing "[daily]" means that agent is OFF LIMITS.
COMMAND 2 — Check for in-progress task logs:
@@ -63,10 +62,9 @@ before choosing a task — is to run these two commands. Not later. NOW.
COMMAND 1 — Check for open weekly agent PRs:
gh pr list --repo PR0M3TH3AN/bitvid --state open --json number,title,createdAt,author --limit 100 | grep -i "\[weekly\]"
curl -s "https://api.github.com/repos/PR0M3TH3AN/bitvid/pulls?state=open&per_page=100" | jq '{count: length, titles: [.[].title]}'
If `gh` is not available, use this fallback:
curl -s "https://api.github.com/repos/PR0M3TH3AN/bitvid/pulls?state=open&per_page=100" | grep -o '"title":"[^"]*\[weekly\][^"]*"'
Review the output. Any title containing "[weekly]" means that agent is OFF LIMITS.
COMMAND 2 — Check for in-progress task logs:
+13 -24
View File
@@ -76,17 +76,12 @@ If you arrived here from the meta prompt and already ran these commands and past
Run this command:
```bash
gh pr list --repo PR0M3TH3AN/bitvid --state open --json number,title,createdAt,author --limit 100 | grep -i "\[daily\]"
curl -s "https://api.github.com/repos/PR0M3TH3AN/bitvid/pulls?state=open&per_page=100" | jq '{count: length, titles: [.[].title]}'
```
If `gh` is unavailable, use this fallback:
```bash
curl -s "https://api.github.com/repos/PR0M3TH3AN/bitvid/pulls?state=open&per_page=100" | grep -o '"title":"[^"]*\[daily\][^"]*"'
```
**Paste the complete raw output.** If the command returns nothing or errors, write: `OUTPUT: (empty — no results)`
**Paste the complete raw output.** If the command returns nothing, write: `OUTPUT: (empty — no results)`
Every agent name that appears in these PR titles is **OFF LIMITS** — do not select it.
Review the titles in the output. Every agent name that appears in a PR title containing `[daily]` is **OFF LIMITS** — do not select it.
### COMMAND 2 — Check the task log for incomplete runs
@@ -114,7 +109,7 @@ or:
EXCLUDED AGENTS: (none)
```
**If Command 1 failed** (network error, API limit, `gh`/`curl` unavailable): you MUST still check the task log directory (Command 2). Log a warning in your summary that PR-based claim checking was unavailable.
**If Command 1 failed** (network error, API rate limit, `curl`/`jq` unavailable): you MUST still check the task log directory (Command 2). Log a warning in your summary that PR-based claim checking was unavailable.
**Do not proceed to Step 1 until you have pasted command outputs and written your exclusion list.**
@@ -164,25 +159,19 @@ EXCLUDED AGENTS: (none)
You must create a visible claim before doing any work. This claim is a **distributed lock** that prevents agents on other platforms (Claude Code, Codex, Jules) from picking up the same task.
### 2a. Create your working branch and claim via draft PR
### 2a. Create your working branch and push a claim
1. Create your working branch.
2. Make a minimal initial commit (e.g., create a new `context/CONTEXT_<timestamp>.md` with the task scope).
3. Push the branch and open a **draft PR**:
```bash
gh pr create --draft \
--title "[daily] <agent-name>: <brief task description>" \
--body "Claimed by daily scheduler at $(date -u +%Y-%m-%dT%H:%M:%SZ). Work in progress."
```
4. Verify the draft PR was created successfully before proceeding.
3. Push the branch immediately to make it visible to other agents.
### 2b. Race condition check
After creating the draft PR, immediately re-check:
After pushing, re-check for competing claims:
```bash
gh pr list --repo PR0M3TH3AN/bitvid --state open --json number,title,createdAt --limit 100 | grep -i "<agent-name>"
curl -s "https://api.github.com/repos/PR0M3TH3AN/bitvid/pulls?state=open&per_page=100" | jq '{count: length, titles: [.[].title]}'
```
If you see another PR for this agent that was created *before* yours (by a different agent instance), close your PR with `gh pr close <your-pr-number>` and go back to Step 1 to select the next agent.
If you see another PR for this agent that was created *before* yours, abandon your branch and go back to Step 1 to select the next agent.
### 2c. Log "started" in the task log immediately
@@ -209,7 +198,7 @@ Use the current UTC timestamp. The file content should be:
Commit and push this log file to your branch. This `started` entry serves as a secondary lock: other scheduler instances will see it and skip this agent.
**If `gh` is unavailable:** You MUST still create the `started` log file and push it. The log file is your minimum viable claim.
**The `started` log file is your primary claim mechanism.** Push it immediately so other agents can see it.
---
@@ -279,7 +268,7 @@ Use the current UTC timestamp (which will be later than the `started` file). The
- If the agent prompt file is **empty or missing**, skip it, log the run as `failed` with summary `"Prompt file empty or missing"`, and proceed to the **next agent** in the roster.
- If a task **fails mid-execution** (test failures, build errors), log the run as `failed` with a summary describing the failure. Still commit the log file and any partial artifacts.
- If the task log directory is **missing**, create it: `mkdir -p docs/agents/task-logs/daily/`.
- If `gh` or `curl` is **unavailable or errors**, fall back to log-file-only claiming (the `started` file). Log a warning in your summary that PR-based claim checking was degraded.
- If `curl` or `jq` is **unavailable or errors**, fall back to log-file-only claiming (the `started` file). Log a warning in your summary that PR-based claim checking was degraded.
---
@@ -287,9 +276,9 @@ Use the current UTC timestamp (which will be later than the `started` file). The
| Layer | Mechanism | Catches |
|-------|-----------|---------|
| **Pre-flight gate** | Scan ALL open `[daily]` PRs via `gh`/`curl` | Agents claimed by any platform |
| **Pre-flight gate** | Scan ALL open `[daily]` PRs via `curl` | Agents claimed by any platform |
| **Pre-flight gate** | Check task log dir for `started` files | Agents in progress (even without PR) |
| **Step 2a** | Create draft PR as lock | Cross-platform visibility |
| **Step 2a** | Push branch with claim commit | Cross-platform visibility |
| **Step 2b** | Race condition re-check | Simultaneous claims |
| **Step 2c** | Create `started` log file immediately | Crash recovery — rotation advances |
@@ -77,7 +77,7 @@ WORKFLOW
2) CI health check (evidence gathering)
- Gather recent CI run results using one of:
- GitHub Actions UI/manual inspection, OR
- GitHub API / `gh` CLI (only if available; do not assume).
- GitHub API via `curl` (e.g., `curl -s "https://api.github.com/repos/PR0M3TH3AN/bitvid/actions/runs?per_page=20"`).
- Identify candidate flakes:
- same test fails on one run but passes on another with no relevant code change
- failures are timing-related, network-mocking-related, ordering-related
+13 -24
View File
@@ -76,17 +76,12 @@ If you arrived here from the meta prompt and already ran these commands and past
Run this command:
```bash
gh pr list --repo PR0M3TH3AN/bitvid --state open --json number,title,createdAt,author --limit 100 | grep -i "\[weekly\]"
curl -s "https://api.github.com/repos/PR0M3TH3AN/bitvid/pulls?state=open&per_page=100" | jq '{count: length, titles: [.[].title]}'
```
If `gh` is unavailable, use this fallback:
```bash
curl -s "https://api.github.com/repos/PR0M3TH3AN/bitvid/pulls?state=open&per_page=100" | grep -o '"title":"[^"]*\[weekly\][^"]*"'
```
**Paste the complete raw output.** If the command returns nothing or errors, write: `OUTPUT: (empty — no results)`
**Paste the complete raw output.** If the command returns nothing, write: `OUTPUT: (empty — no results)`
Every agent name that appears in these PR titles is **OFF LIMITS** — do not select it.
Review the titles in the output. Every agent name that appears in a PR title containing `[weekly]` is **OFF LIMITS** — do not select it.
### COMMAND 2 — Check the task log for incomplete runs
@@ -114,7 +109,7 @@ or:
EXCLUDED AGENTS: (none)
```
**If Command 1 failed** (network error, API limit, `gh`/`curl` unavailable): you MUST still check the task log directory (Command 2). Log a warning in your summary that PR-based claim checking was unavailable.
**If Command 1 failed** (network error, API rate limit, `curl`/`jq` unavailable): you MUST still check the task log directory (Command 2). Log a warning in your summary that PR-based claim checking was unavailable.
**Do not proceed to Step 1 until you have pasted command outputs and written your exclusion list.**
@@ -159,25 +154,19 @@ EXCLUDED AGENTS: (none)
You must create a visible claim before doing any work. This claim is a **distributed lock** that prevents agents on other platforms (Claude Code, Codex, Jules) from picking up the same task.
### 2a. Create your working branch and claim via draft PR
### 2a. Create your working branch and push a claim
1. Create your working branch.
2. Make a minimal initial commit (e.g., create a new `context/CONTEXT_<timestamp>.md` with the task scope).
3. Push the branch and open a **draft PR**:
```bash
gh pr create --draft \
--title "[weekly] <agent-name>: <brief task description>" \
--body "Claimed by weekly scheduler at $(date -u +%Y-%m-%dT%H:%M:%SZ). Work in progress."
```
4. Verify the draft PR was created successfully before proceeding.
3. Push the branch immediately to make it visible to other agents.
### 2b. Race condition check
After creating the draft PR, immediately re-check:
After pushing, re-check for competing claims:
```bash
gh pr list --repo PR0M3TH3AN/bitvid --state open --json number,title,createdAt --limit 100 | grep -i "<agent-name>"
curl -s "https://api.github.com/repos/PR0M3TH3AN/bitvid/pulls?state=open&per_page=100" | jq '{count: length, titles: [.[].title]}'
```
If you see another PR for this agent that was created *before* yours (by a different agent instance), close your PR with `gh pr close <your-pr-number>` and go back to Step 1 to select the next agent.
If you see another PR for this agent that was created *before* yours, abandon your branch and go back to Step 1 to select the next agent.
### 2c. Log "started" in the task log immediately
@@ -204,7 +193,7 @@ Use the current UTC timestamp. The file content should be:
Commit and push this log file to your branch. This `started` entry serves as a secondary lock: other scheduler instances will see it and skip this agent.
**If `gh` is unavailable:** You MUST still create the `started` log file and push it. The log file is your minimum viable claim.
**The `started` log file is your primary claim mechanism.** Push it immediately so other agents can see it.
---
@@ -276,7 +265,7 @@ Use the current UTC timestamp (which will be later than the `started` file). The
- If the agent prompt file is **empty or missing**, skip it, log the run as `failed` with summary `"Prompt file empty or missing"`, and proceed to the **next agent** in the roster.
- If a task **fails mid-execution** (test failures, build errors), log the run as `failed` with a summary describing the failure. Still commit the log file and any partial artifacts.
- If the task log directory is **missing**, create it: `mkdir -p docs/agents/task-logs/weekly/`.
- If `gh` or `curl` is **unavailable or errors**, fall back to log-file-only claiming (the `started` file). Log a warning in your summary that PR-based claim checking was degraded.
- If `curl` or `jq` is **unavailable or errors**, fall back to log-file-only claiming (the `started` file). Log a warning in your summary that PR-based claim checking was degraded.
---
@@ -284,9 +273,9 @@ Use the current UTC timestamp (which will be later than the `started` file). The
| Layer | Mechanism | Catches |
|-------|-----------|---------|
| **Pre-flight gate** | Scan ALL open `[weekly]` PRs via `gh`/`curl` | Agents claimed by any platform |
| **Pre-flight gate** | Scan ALL open `[weekly]` PRs via `curl` | Agents claimed by any platform |
| **Pre-flight gate** | Check task log dir for `started` files | Agents in progress (even without PR) |
| **Step 2a** | Create draft PR as lock | Cross-platform visibility |
| **Step 2a** | Push branch with claim commit | Cross-platform visibility |
| **Step 2b** | Race condition re-check | Simultaneous claims |
| **Step 2c** | Create `started` log file immediately | Crash recovery — rotation advances |
@@ -128,7 +128,7 @@ PR METADATA (PR number, author) — RULES
Only include PR number and author if you can **verify** them via:
- merge commit messages that include PR numbers, OR
- an available local tool/config that exposes PR metadata (e.g., `gh`)
- the GitHub API via `curl` (e.g., `curl -s "https://api.github.com/repos/PR0M3TH3AN/bitvid/pulls?state=closed&per_page=50" | jq '[.[] | {number, title, merged_at: .merged_at}]'`)
If not verifiable:
- omit PR numbers/authors and keep bullets keyed to commit subjects/hashes.
@@ -73,21 +73,22 @@ WORKFLOW
- security-sensitive boundaries and logging policy
- Confirm tooling availability:
- `npm` available
- PR checkout method available (`gh` CLI or equivalent)
If `gh` is not available, fall back to manual instructions in the audit log.
- `curl` and `jq` available for GitHub API queries
If `curl` is not available, document that PR enumeration was not possible in the audit log.
2) Enumerate open PRs
- Preferred: `curl` command (works without gh auth):
```bash
curl -s "https://api.github.com/repos/PR0M3TH3AN/bitvid/pulls?state=open&per_page=100" | jq -c '.[] | {number: .number, title: .title, created_at: .created_at, author: .user.login}'
```
- Alternative: `gh pr list` (if available/configured).
- Otherwise: document that PR enumeration was not possible in this environment.
3) For each PR: checkout and run verification
Checkout:
- Preferred: `gh pr checkout <num>`
- Otherwise: fetch the PR branch via git remote refs (only if you can verify).
- Fetch the PR branch via git remote refs:
```bash
git fetch origin pull/<num>/head:pr-<num> && git checkout pr-<num>
```
Install + checks (verify the script names first):
- `npm ci` (preferred) or `npm install` if CI install is not supported
@@ -76,11 +76,16 @@ WORKFLOW
- Gather branch refs:
- `git for-each-ref --sort=-committerdate --format='%(committerdate:short) %(refname:short)' refs/heads/ai`
Optional method (only if tooling is available and policy allows):
- Use `gh` CLI or other configured tooling to fetch:
- PR links/status
- issue links/priorities
If not available: do not guess links; report locally-derived identifiers.
Optional method (use curl to query the GitHub API):
- Fetch open PRs:
```
curl -s "https://api.github.com/repos/PR0M3TH3AN/bitvid/pulls?state=open&per_page=100" | jq '{count: length, titles: [.[].title]}'
```
- Fetch recently closed/merged PRs:
```
curl -s "https://api.github.com/repos/PR0M3TH3AN/bitvid/pulls?state=closed&per_page=50&sort=updated&direction=desc" | jq '[.[] | {title: .title, merged: .merged_at, number: .number}]'
```
If curl is unavailable: do not guess links; report locally-derived identifiers.
3) Normalize items into report sections
For each item discovered, capture:
+15 -7
View File
@@ -13,18 +13,25 @@ function runCommand(command, args = [], options = {}) {
}
function getOpenPRs() {
console.log('Fetching open PRs...');
console.log('Fetching open PRs via GitHub API...');
try {
const res = spawnSync('gh', ['pr', 'list', '--json', 'number,headRefName,baseRefName,url'], { encoding: 'utf-8' });
const res = spawnSync('curl', ['-s', 'https://api.github.com/repos/PR0M3TH3AN/bitvid/pulls?state=open&per_page=100'], { encoding: 'utf-8' });
if (res.error) {
console.error('Error fetching PRs (gh CLI not installed?):', res.error.message);
console.error('Error fetching PRs (curl not available?):', res.error.message);
return [];
}
if (res.status !== 0) {
console.error('Error fetching PRs:', res.stderr);
return [];
}
return JSON.parse(res.stdout);
const apiPRs = JSON.parse(res.stdout);
// Map GitHub API response to the shape we need
return apiPRs.map(pr => ({
number: pr.number,
headRefName: pr.head.ref,
baseRefName: pr.base.ref,
url: pr.html_url
}));
} catch (e) {
console.error('Exception fetching PRs:', e);
return [];
@@ -52,15 +59,16 @@ async function main() {
for (const pr of openPRs) {
console.log(`\n=== Processing PR #${pr.number}: ${pr.url} ===`);
try {
// Checkout PR
runCommand('gh', ['pr', 'checkout', pr.number]);
// Checkout PR via git fetch
runCommand('git', ['fetch', 'origin', `pull/${pr.number}/head:pr-${pr.number}`]);
runCommand('git', ['checkout', `pr-${pr.number}`]);
// Set Environment Variables
const env = {
...process.env,
PR_NUMBER: pr.number.toString(),
GITHUB_BASE_REF: pr.baseRefName,
// Assuming origin is the base repo or gh pr checkout handled the remote setup.
// Assuming origin is the base repo.
// automated-pr-review.mjs handles missing GITHUB_BASE_REPO_URL by defaulting to upstream/origin.
};
+13 -8
View File
@@ -258,16 +258,20 @@ async function main() {
const isAll = process.argv.includes('--all');
if (isAll) {
console.log('Fetching all open PRs...');
// Get list of open PRs
const listCmd = ['pr', 'list', '--state', 'open', '--json', 'number,baseRefName,headRefName'];
const result = spawnSync('gh', listCmd, { encoding: 'utf-8' });
console.log('Fetching all open PRs via GitHub API...');
// Get list of open PRs via curl (no gh dependency)
const result = spawnSync('curl', ['-s', 'https://api.github.com/repos/PR0M3TH3AN/bitvid/pulls?state=open&per_page=100'], { encoding: 'utf-8' });
if (result.error || result.status !== 0) {
throw new Error(`Failed to list PRs: ${result.stderr || result.error?.message}`);
}
const prs = JSON.parse(result.stdout);
const apiPRs = JSON.parse(result.stdout);
const prs = apiPRs.map(pr => ({
number: pr.number,
baseRefName: pr.base.ref,
headRefName: pr.head.ref
}));
console.log(`Found ${prs.length} open PRs.`);
let hasGlobalFailures = false;
@@ -284,8 +288,9 @@ async function main() {
try {
console.log(`\n=== Processing PR #${pr.number} ===`);
// Checkout PR
runCommand('gh', ['pr', 'checkout', pr.number]);
// Checkout PR via git fetch
runCommand('git', ['fetch', 'origin', `pull/${pr.number}/head:pr-${pr.number}`]);
runCommand('git', ['checkout', `pr-${pr.number}`]);
// Run Review
await reviewPR(pr.number, pr.baseRefName);
@@ -296,7 +301,7 @@ async function main() {
// Continue to next PR
} finally {
// Clean up or reset if needed?
// Since we use gh pr checkout, we are on a different branch.
// Since we fetch and checkout each PR branch, we are on a different branch.
// Next iteration will checkout another branch.
}
}