You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Fix multiple PRs by adding pre-step PR detection and filtering stale branches
The autoloop agent was creating new PRs with hash-suffixed branches on each
iteration instead of pushing to the existing PR. Root causes addressed:
1. Pre-step now detects existing open PRs for the selected program via the
GitHub API and includes `existing_pr` and `head_branch` in autoloop.json.
The agent no longer needs to discover PRs itself — the information is
provided upfront.
2. Agent instructions updated to check `existing_pr` first and only call
`create-pull-request` when no PR exists.
3. sync-branches.md now filters out stale branches with 16-char hex suffixes
(created by the framework), only syncing canonical autoloop/{name} branches.
4. Lock files recompiled.
Agent-Logs-Url: https://github.com/githubnext/tsessebe/sessions/61bed3ca-384f-49d2-8f81-d557fff66250
Co-authored-by: mrjf <180956+mrjf@users.noreply.github.com>
print(f"Existing PR: (none — will create on first accepted iteration)")
452
492
print(f"Deferred (next run): {deferred or '(none)'}")
453
493
print(f"Programs skipped: {[s['name'] for s in skipped] or '(none)'}")
454
494
print(f"Programs unconfigured: {unconfigured or '(none)'}")
@@ -538,6 +578,8 @@ The pre-step has already determined which program to run. Read `/tmp/gh-aw/autol
538
578
-**`selected_file`**: The full path to the program's markdown file (either `.autoloop/programs/<name>/program.md`, `.autoloop/programs/<name>.md`, or `/tmp/gh-aw/issue-programs/<name>.md` for issue-based programs).
539
579
-**`selected_issue`**: The GitHub issue number if the selected program came from an issue, or `null` if it came from a file.
540
580
-**`selected_target_metric`**: The `target-metric` value from the program's frontmatter (a number), or `null` if the program is open-ended. Used to check the [halting condition](#halting-condition) after each accepted iteration.
581
+
-**`existing_pr`**: The PR number (e.g., `42`) of an already-open PR for this program's branch, or `null` if no open PR exists. **If this is not null, you MUST use `push-to-pull-request-branch` to push to this PR — do NOT call `create-pull-request`.**
582
+
-**`head_branch`**: The canonical branch name for this program (e.g., `autoloop/coverage`). Always use this exact branch name — never append suffixes.
541
583
-**`issue_programs`**: A mapping of program name → issue number for all discovered issue-based programs.
542
584
-**`deferred`**: Other programs that were due but will be handled in future runs.
543
585
-**`unconfigured`**: Programs that still have the sentinel or placeholder content.
@@ -550,6 +592,7 @@ If `selected` is not null:
550
592
3. Read the current state of all target files.
551
593
4. Read the state file `{selected}.md` from the repo-memory folder for all state: the ⚙️ Machine State table (scheduling fields) plus the research sections (priorities, lessons, foreclosed avenues, iteration history).
552
594
5. If `selected_issue` is not null, this is an issue-based program — also read the issue comments for any human steering input.
595
+
6.**Check `existing_pr`**: if it is not null, a PR already exists — use `push-to-pull-request-branch` to push commits to it. Only call `create-pull-request` when `existing_pr` is null.
553
596
554
597
## Multiple Programs
555
598
@@ -694,7 +737,7 @@ Each run executes **one iteration for the single selected program**:
694
737
695
738
If the state file does not yet exist, create it in the repo-memory folder using the template defined in the [Repo Memory](#repo-memory) section.
696
739
697
-
3. Note the `PR` field from the Machine State table. If it contains a PR number (e.g., `#42`), that is the **existing draft PR** for this program — you must update it, not create a new one.
740
+
3. Note the `existing_pr` field from `/tmp/gh-aw/autoloop.json`. If it is not null, that is the **existing draft PR** for this program — you must push to it using `push-to-pull-request-branch`, not create a new one. Also check the `PR` field from the Machine State table as a fallback.
698
741
699
742
### Step 2: Analyze and Propose
700
743
@@ -743,15 +786,15 @@ Each run executes **one iteration for the single selected program**:
743
786
- Commit message body (after a blank line): `Run: {run_url}` referencing the GitHub Actions run URL.
744
787
2. Push the commit to the long-running branch `autoloop/{program-name}`.
745
788
3.**Find the existing PR or create one** — follow these steps in order:
746
-
a. Check the `PR` field in the state file's **⚙️ Machine State** table. If it contains a PR number (e.g., `#42`), that is the existing draft PR.
747
-
b. If the state file has no PR number, search GitHub for open PRs with head branch `autoloop/{program-name}`. Use the GitHub API: `GET /repos/{owner}/{repo}/pulls?state=open&head={owner}:autoloop/{program-name}`.
748
-
c. **If an existing PR is found** (from either step a or b): use `push-to-pull-request-branch` to push additional commits to the existing PR. Update the PR body with the latest metric and a summary of the most recent accepted iteration. Add a comment to the PR summarizing the iteration: what changed, old metric, new metric, improvement delta, and a link to the actions run. **Do NOT call `create-pull-request`.**
749
-
d. **If NO PR exists** for `autoloop/{program-name}`: create one using `create-pull-request`:
789
+
a. **First, check `existing_pr` from `/tmp/gh-aw/autoloop.json`.** The pre-step has already looked up the open PR for this program. If `existing_pr` is not null, that is the existing draft PR — skip to step (c).
790
+
b. If `existing_pr` is null, also check the `PR` field in the state file's **⚙️ Machine State** table as a fallback. If it contains a PR number (e.g., `#42`), verify it is still open via the GitHub API.
791
+
c. **If an existing PR is found** (from step a or b): use `push-to-pull-request-branch` to push additional commits to the existing PR. Update the PR body with the latest metric and a summary of the most recent accepted iteration. Add a comment to the PR summarizing the iteration: what changed, old metric, new metric, improvement delta, and a link to the actions run. **Do NOT call `create-pull-request`.**
792
+
d. **If NO PR exists** for `autoloop/{program-name}` (both `existing_pr` is null AND the state file has no PR): create one using `create-pull-request`:
750
793
- Branch: `autoloop/{program-name}` (the branch you already created in Step 3 — do NOT let the framework auto-generate a branch name)
751
794
- Title: `[Autoloop: {program-name}]`
752
795
- Body includes: a summary of the program goal, link to the steering issue, the current best metric, and AI disclosure: `🤖 *This PR is maintained by Autoloop. Each accepted iteration adds a commit to this branch.*`
753
796
754
-
> ⚠️ **Never create a new PR if one already exists for `autoloop/{program-name}`.** Each program must have exactly one draft PR at any time. If you are unsure whether a PR exists, check the GitHub API before calling `create-pull-request`.
797
+
> ⚠️ **Never create a new PR if one already exists for `autoloop/{program-name}`.** Each program must have exactly one draft PR at any time. The pre-step provides `existing_pr` in autoloop.json — always check it first. Only call `create-pull-request` when `existing_pr` is null AND the state file has no PR number.
755
798
4. Ensure the steering issue exists (see [Steering Issue](#steering-issue) below). Add a comment to the steering issue linking to the commit and actions run.
756
799
5. Add an entry to the experiment log issue.
757
800
6. Update the state file `{program-name}.md` in the repo-memory folder:
@@ -1148,9 +1191,10 @@ After each iteration, prepend an entry to the **📊 Iteration History** section
1148
1191
> ❌ **Do NOT create a new branch with a suffix for each iteration.**
> Use the `head_branch` field from `autoloop.json` — it is always the canonical name.
1151
1195
1152
1196
> ❌ **Do NOT create a new PR if one already exists for `autoloop/{program-name}`.**
1153
-
> Always check the state file's `PR` field and the GitHub API before calling `create-pull-request`. If a PR exists, use `push-to-pull-request-branch` instead.
1197
+
> The pre-step provides `existing_pr` in `autoloop.json`. If it is not null, **always** use `push-to-pull-request-branch` — never call `create-pull-request`. Only create a PR when `existing_pr` is null AND the state file has no PR number.
1154
1198
1155
1199
> ❌ **Do NOT let the gh-aw framework auto-generate a branch name when creating a PR.**
1156
1200
> Always specify the branch explicitly as `autoloop/{program-name}` when calling `create-pull-request`.
0 commit comments