Skip to content

Commit ee86d0f

Browse files
mrjfclaude
andauthored
Autoloop: bootstrap via draft PR instead of direct push (#285)
* Autoloop bootstrap: use draft PR instead of direct push Stop committing template files directly to the default branch during bootstrap. Instead, leave them unstaged so the agent creates a draft PR, giving maintainers a chance to review before merge. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Move autoloop config directory from .github/autoloop/ to .autoloop/ Aligns with the w3k deployment convention — keeps autoloop config at the repo root rather than nested under .github/. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent d1d8845 commit ee86d0f

File tree

1 file changed

+20
-18
lines changed

1 file changed

+20
-18
lines changed

workflows/autoloop.md

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,8 @@ steps:
7070
import os, json, re, glob, sys
7171
from datetime import datetime, timezone, timedelta
7272
73-
programs_dir = ".github/autoloop/programs"
74-
state_file = ".github/autoloop/state.json"
73+
programs_dir = ".autoloop/programs"
74+
state_file = ".autoloop/state.json"
7575
template_file = os.path.join(programs_dir, "example.md")
7676
7777
# Bootstrap: create programs directory and template if missing
@@ -118,17 +118,14 @@ steps:
118118
])
119119
with open(template_file, "w") as f:
120120
f.write(template)
121-
# Commit the template so the user can see and edit it
122-
os.system(f'git add "{template_file}"')
123-
os.system('git commit -m "[Autoloop] Bootstrap: add program template for configuration"')
124-
os.system('git push')
125-
print(f"BOOTSTRAPPED: created {template_file} and pushed to repo")
121+
# Leave the template unstaged — the agent will create a draft PR with it
122+
print(f"BOOTSTRAPPED: created {template_file} locally (agent will create a draft PR)")
126123
127124
# Find all program files
128125
program_files = sorted(glob.glob(os.path.join(programs_dir, "*.md")))
129126
if not program_files:
130127
# Fallback to single-file locations
131-
for path in [".github/autoloop/program.md", "program.md"]:
128+
for path in [".autoloop/program.md", "program.md"]:
132129
if os.path.isfile(path):
133130
program_files = [path]
134131
break
@@ -251,18 +248,18 @@ An iterative optimization agent that proposes changes, evaluates them against a
251248
Take heed of **instructions**: "${{ steps.sanitized.outputs.text }}"
252249

253250
If these are non-empty (not ""), then you have been triggered via `/autoloop <instructions>`. The instructions may be:
254-
- **A one-off directive targeting a specific program**: e.g., `/autoloop training: try a different approach to the loss function`. The text before the colon is the program name (matching a file in `.github/autoloop/programs/`). Execute it as a single iteration for that program, then report results.
251+
- **A one-off directive targeting a specific program**: e.g., `/autoloop training: try a different approach to the loss function`. The text before the colon is the program name (matching a file in `.autoloop/programs/`). Execute it as a single iteration for that program, then report results.
255252
- **A general directive**: e.g., `/autoloop try cosine annealing`. If no program name prefix is given and only one program exists, use that one. If multiple exist, ask which program to target.
256253
- **A configuration change**: e.g., `/autoloop training: set metric to accuracy instead of loss`. Update the relevant program file and confirm.
257254

258255
Then exit — do not run the normal loop after completing the instructions.
259256

260257
## Multiple Programs
261258

262-
Autoloop supports **multiple independent optimization loops** in the same repository. Each loop is defined by a separate markdown file in `.github/autoloop/programs/`. For example:
259+
Autoloop supports **multiple independent optimization loops** in the same repository. Each loop is defined by a separate markdown file in `.autoloop/programs/`. For example:
263260

264261
```
265-
.github/autoloop/programs/
262+
.autoloop/programs/
266263
├── training.md ← optimize model training
267264
├── coverage.md ← maximize test coverage
268265
└── build-perf.md ← minimize build time
@@ -299,7 +296,7 @@ This lets you run a fast coverage check every hour while running a slow training
299296

300297
## Program Definition
301298

302-
Each program file in `.github/autoloop/programs/` defines three things:
299+
Each program file in `.autoloop/programs/` defines three things:
303300

304301
1. **Goal**: What the agent is trying to optimize (natural language description)
305302
2. **Target**: Which files the agent is allowed to modify
@@ -309,7 +306,7 @@ The **program name** is the filename without the `.md` extension (e.g., `trainin
309306

310307
### Setup Guard
311308

312-
A template program file is installed at `.github/autoloop/programs/example.md`. **Programs will not run until the user has edited them.** Each template contains a sentinel line:
309+
A template program file is installed at `.autoloop/programs/example.md`. **Programs will not run until the user has edited them.** Each template contains a sentinel line:
313310

314311
```
315312
<!-- AUTOLOOP:UNCONFIGURED -->
@@ -326,17 +323,22 @@ At the start of every run, check each program file for this sentinel. For any pr
326323

327324
If **all** programs are unconfigured, exit after creating the setup issues. Otherwise, proceed with the configured programs.
328325

326+
**Important**: When creating or modifying template/program files during setup, always do so via a draft PR — never commit directly to the default branch. Only iteration state files (`state.json`) should be committed directly.
327+
329328
### Reading Programs
330329

331330
The pre-step has already determined which programs are due, unconfigured, or skipped. Read `/tmp/gh-aw/autoloop.json` at the start of your run to get:
332331

333332
- **`due`**: List of program names to run iterations for this run.
334-
- **`unconfigured`**: Programs that still have the sentinel or placeholder content — run the **Setup Guard** for each of these (create setup issues).
333+
- **`unconfigured`**: Programs that still have the sentinel or placeholder content. For each unconfigured program:
334+
1. Check whether the program file actually exists on the default branch (use `git show HEAD:.autoloop/programs/{name}.md`). If it does NOT exist on the default branch, **you must create a draft PR** (branch: `autoloop/setup-template`) that adds the template file. The pre-step may have created the file locally in the working directory, so it will be available to commit — just create a branch, commit it, and open the PR.
335+
2. If no setup issue exists for this program, create one (see Setup Guard above).
336+
3. If the file already exists on the default branch and a setup issue already exists, then no action is needed for this program.
335337
- **`skipped`**: Programs not due yet based on their per-program schedule — ignore these entirely.
336-
- **`no_programs`**: If `true`, no program files exist at all — create a single issue explaining how to add a program.
338+
- **`no_programs`**: If `true`, no program files exist at all. The pre-step should have bootstrapped a template locally. Follow the same steps as `unconfigured` above — create a draft PR with the template and a setup issue.
337339

338340
For each program in `due`:
339-
1. Read the program file from `.github/autoloop/programs/{name}.md`.
341+
1. Read the program file from `.autoloop/programs/{name}.md`.
340342
2. Parse the three sections: Goal, Target, Evaluation.
341343
3. Read the current state of all target files.
342344
4. Read repo memory for that program's metric history (keyed by program name).
@@ -348,7 +350,7 @@ Each run executes **one iteration per configured program**. For each program:
348350
### Step 1: Read State
349351

350352
1. Read the program file to understand the goal, targets, and evaluation method.
351-
2. Read `.github/autoloop/state.json` for this program's `best_metric` and `iteration_count`.
353+
2. Read `.autoloop/state.json` for this program's `best_metric` and `iteration_count`.
352354
3. Read repo memory (keyed by program name) for detailed history:
353355
- `history`: Summary of recent iterations (last 20).
354356
- `rejected_approaches`: Approaches that were tried and failed (to avoid repeating).
@@ -444,7 +446,7 @@ Maintain a single open issue **per program** titled `[Autoloop: {program-name}]
444446

445447
Autoloop uses **two persistence layers**:
446448

447-
### 1. State file (`.github/autoloop/state.json`) — lightweight, committed to repo
449+
### 1. State file (`.autoloop/state.json`) — lightweight, committed to repo
448450

449451
This file is read by the **pre-step** (before the agent starts) to decide which programs are due. The agent **must update this file and commit it** at the end of every iteration. This is the only way the pre-step can check schedules, plateaus, and pause flags on future runs.
450452

0 commit comments

Comments
 (0)