Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/workflows/autoloop.md
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,6 @@ Examples:
4. **Rejected or errored iterations** do not commit — changes are discarded.
5. A **single draft PR** is created for the branch on the first accepted iteration. Future accepted iterations push additional commits to the same PR.
6. The branch may be **merged into the default branch** at any time (by a maintainer or CI). After merging, the branch continues to be used for future iterations — it is never deleted while the program is active. On the next iteration, the branch is automatically reset to the default branch (see step 2) so that already-merged commits do not cause patch conflicts.
7. A **sync workflow** automatically merges the default branch into all active `autoloop/*` branches whenever the default branch changes, keeping them up to date.

### Cross-Linking

Expand Down
550 changes: 0 additions & 550 deletions .github/workflows/sync-branches.lock.yml

This file was deleted.

169 changes: 0 additions & 169 deletions .github/workflows/sync-branches.md

This file was deleted.

14 changes: 6 additions & 8 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ autoloop/
├── AGENTS.md ← you are here
├── workflows/ ← Agentic Workflow definitions
│ ├── autoloop.md ← main autoloop workflow (compiled by gh-aw)
│ ├── sync-branches.md ← syncs default branch into autoloop/* branches
│ ├── shared/ ← shared workflow fragments
│ │ └── reporting.md
│ └── scripts/ ← standalone scripts invoked from steps
Expand Down Expand Up @@ -72,7 +71,7 @@ The workflow (`workflows/autoloop.md`) is compiled by `gh aw compile` into `.git
6. Updates the program's state file in repo-memory with all state (Machine State table + research sections)
7. If the program has a `target-metric` and the metric is reached, marks it as completed (removes `autoloop-program` label, adds `autoloop-completed` label for issue-based programs)

A companion workflow (`workflows/sync-branches.md`) runs on every push to the default branch and merges it into all active `autoloop/*` program branches, keeping them up to date.
Branch freshness is handled by the iteration loop itself: each iteration's Step 3 (in `workflows/autoloop.md`, "Iteration Loop" → step "Branch Setup") fast-forwards or merges `origin/main` into the program's `autoloop/*` branch as needed. No separate sync workflow is required.

### Evolution Strategy

Expand Down Expand Up @@ -134,9 +133,8 @@ Programs run on a schedule, but can also be triggered manually:
To deploy the workflow to a repository:

1. Copy `workflows/autoloop.md` to `.github/workflows/autoloop.md` in the target repo
2. Copy `workflows/sync-branches.md` to `.github/workflows/sync-branches.md` in the target repo
3. Copy `workflows/shared/` to `.github/workflows/shared/` in the target repo
4. Copy `workflows/scripts/` to `.github/workflows/scripts/` in the target repo
5. Run `gh aw compile autoloop` and `gh aw compile sync-branches` to generate the lock files
6. Copy program directories to `.autoloop/programs/` in the target repo
7. Commit and push
2. Copy `workflows/shared/` to `.github/workflows/shared/` in the target repo
3. Copy `workflows/scripts/` to `.github/workflows/scripts/` in the target repo
4. Run `gh aw compile autoloop` to generate the lock file
5. Copy program directories to `.autoloop/programs/` in the target repo
6. Commit and push
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,6 @@ The command is handled by the `autoloop` Agentic Workflow — it is **not** a Gi
autoloop/
├── workflows/ ← Agentic Workflow definitions
│ ├── autoloop.md ← the workflow (compiled by gh aw)
│ ├── sync-branches.md ← syncs default branch into autoloop/* branches
│ └── shared/
│ └── reporting.md
├── .autoloop/
Expand Down
5 changes: 2 additions & 3 deletions install.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,9 @@ rm -rf /tmp/autoloop

```bash
gh aw compile autoloop
gh aw compile sync-branches
```

**What this does**: Generates `.github/workflows/autoloop.lock.yml` and `.github/workflows/sync-branches.lock.yml` from the workflow definitions.
**What this does**: Generates `.github/workflows/autoloop.lock.yml` from the workflow definition.

## Step 5: Create a Branch, Commit, and Open a Pull Request

Expand Down Expand Up @@ -141,7 +140,7 @@ Optionally, you may copy existing examples from the [`.autoloop/programs/`](.aut

### Compile fails

- Ensure `.github/workflows/autoloop.md` and `.github/workflows/sync-branches.md` exist
- Ensure `.github/workflows/autoloop.md` exists
- Ensure `.github/workflows/shared/` directory was copied
- Re-run `gh aw compile autoloop` with `--verbose` for details

Expand Down
86 changes: 0 additions & 86 deletions tests/test_scheduling.py
Original file line number Diff line number Diff line change
Expand Up @@ -685,92 +685,6 @@ def test_clone_before_scheduling(self):
)


class TestSyncBranchesCredentialOrdering:
"""Verify that Git credentials are configured before the merge/push step.

The sync-branches workflow merges the default branch into autoloop/*
branches. Merge commits require a Git identity (user.name/user.email)
and pushes/fetches need an authenticated remote URL. Both must be
configured before the merge step runs.
"""

CRED_STEP = "Set up Git identity and authentication"
MERGE_STEP = "Merge default branch into all autoloop program branches"

def _load_steps(self):
"""Return the list of pre-step names from workflows/sync-branches.md."""
import os

wf_path = os.path.join(os.path.dirname(__file__), "..", "workflows", "sync-branches.md")
with open(wf_path) as f:
content = f.read()
step_names = []
for m in re.finditer(r'^\s*-\s*name:\s*(.+)$', content, re.MULTILINE):
step_names.append(m.group(1).strip())
return step_names

def _load_lock_steps(self):
"""Return the list of step names from the agent job in
.github/workflows/sync-branches.lock.yml.

Parsed with a regex (rather than PyYAML) so the test has no
external dependencies beyond pytest.
"""
import os

lock_path = os.path.join(
os.path.dirname(__file__), "..", ".github", "workflows", "sync-branches.lock.yml"
)
with open(lock_path) as f:
content = f.read()
# Restrict to the 'agent:' job body so we don't pick up step names
# from other jobs (e.g. 'activation').
agent_match = re.search(r"^ agent:\n((?: .*\n|\n)+)", content, re.MULTILINE)
if not agent_match:
return []
agent_body = agent_match.group(1)
# Step names appear as either ' - name: <Name>' or
# ' name: <Name>' (when the step starts with '- env:').
step_names = []
for m in re.finditer(r'^\s{6,8}(?:- )?name:\s*(.+)$', agent_body, re.MULTILINE):
step_names.append(m.group(1).strip())
return step_names

def test_cred_step_exists(self):
"""A step that configures Git identity/auth must exist in the source."""
steps = self._load_steps()
assert self.CRED_STEP in steps, (
f"Expected step '{self.CRED_STEP}' not found. Steps: {steps}"
)

def test_creds_before_merge(self):
"""The credential step must come before the merge step in the source."""
steps = self._load_steps()
cred_idx = steps.index(self.CRED_STEP)
merge_idx = steps.index(self.MERGE_STEP)
assert cred_idx < merge_idx, (
f"'{self.CRED_STEP}' (index {cred_idx}) must come before "
f"'{self.MERGE_STEP}' (index {merge_idx}). Steps: {steps}"
)

def test_lock_creds_before_merge(self):
"""In the compiled lock file, Configure Git credentials must come before the merge step."""
steps = self._load_lock_steps()
cred_names = [s for s in steps if "Configure Git credentials" in s]
assert cred_names, (
f"No 'Configure Git credentials' step found in lock file. Steps: {steps}"
)
merge_names = [s for s in steps if "Merge default branch" in s]
assert merge_names, (
f"No merge step found in lock file. Steps: {steps}"
)
cred_idx = steps.index(cred_names[0])
merge_idx = steps.index(merge_names[0])
assert cred_idx < merge_idx, (
f"'Configure Git credentials' (index {cred_idx}) must come before "
f"merge step (index {merge_idx}). Steps: {steps}"
)


# ---------------------------------------------------------------------------
# Single-PR-per-program invariant: safe-outputs config + existing_pr lookup
Expand Down
1 change: 0 additions & 1 deletion workflows/autoloop.md
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,6 @@ Examples:
4. **Rejected or errored iterations** do not commit — changes are discarded.
5. A **single draft PR** is created for the branch on the first accepted iteration. Future accepted iterations push additional commits to the same PR.
6. The branch may be **merged into the default branch** at any time (by a maintainer or CI). After merging, the branch continues to be used for future iterations — it is never deleted while the program is active. On the next iteration, the branch is automatically reset to the default branch (see step 2) so that already-merged commits do not cause patch conflicts.
7. A **sync workflow** automatically merges the default branch into all active `autoloop/*` branches whenever the default branch changes, keeping them up to date.

### Cross-Linking

Expand Down
Loading
Loading