Unattended overnight architecture-improvement loop for a git repository. A deterministic
bash state machine automates Matt Pocock's improve-architecture
skill: it runs the skill, triggers an opencode session to implement each Strong
suggestion, and follows each implementation with a fresh-context review — until the codebase
scan reports no Strong candidates left.
archloop-loop.sh re-runs run.sh against a target repo until the scan reports no Strong
candidates, or the MAX_ROUNDS safety cap is hit (default 8 — PARKED items can be
re-proposed, so the cap stops a night that never converges).
Each run.sh round walks a fixed pipeline:
- Preflight — abort unless the canonical checkout is clean, on
main, and baseline tests + lint are green. The canonical tree is never touched. - Scan — one session reads the architecture-scan skill and lists Strong candidates
(duplication or split contracts spanning 3+ sites, or a silent failure mode; the fix
must remove more code than it adds). One plan covers every Strong candidate, best
first. Nothing qualifies →
NONEverdict, stop. - Implement — one session per item, in an isolated worktree, keeping tests + lint green.
- Gate — one fresh-context review session per item.
SHIPorPARKper item; a PARK resets the branch and costs one item, not the night. - Merge + push — SHIPped items merge
--no-ffback intomainand push at the end of the run (ARCHLOOP_MERGE=0/ARCHLOOP_PUSH=0disable).
Every stage reads and writes files under the repo's .archloop/ directory — artifacts,
not memory. The run is crash-restartable and fully auditable.
The orchestrator is a script, not a model: the sequence is a fixed state machine —
deterministic, free, restartable, immune to overnight context rot. Models think inside
stages; the script sequences them and greps one-word verdict files. One fresh opencode run session is one stage boundary.
Architecture debt is exactly the work nobody picks up: suggestions sit in review, and the sessions that could apply them never start. archloop makes the loop unattended: scan, implement, review, repeat — every night if you want, with every change gated by a fresh-context review before it can merge.
One run.sh round — the script sequences, models think inside stages:
flowchart TD
P["Preflight — clean tree · on main · baseline green"] -->|"abort"| X["ABORT — canonical tree untouched"]
P --> S["Scan — list Strong candidates, plan best first"]
S -->|"NONE verdict"| D["Stop — nothing Strong left"]
S -->|"PLANNED"| I["Implement — isolated worktree, tests + lint green"]
I --> G["Gate — fresh-context review per item"]
G -->|"SHIP"| N{"more items?"}
G -->|"PARK — branch reset, costs one item"| N
N -->|"yes"| I
N -->|"no"| M["Merge SHIPped --no-ff · push"]
M --> R["REPORT.md + ledger in target .archloop/"]
What makes a find Strong — and where each one ends up:
flowchart LR
A["Architecture scan"] --> B{"Strong candidate?"}
B -->|"duplication or split contract across 3+ sites, or a silent failure mode — and the fix removes more code than it adds"| C["Planned, best first"]
B -->|"everything else"| W["Weak — never planned"]
C --> E["Fresh-context review in a worktree"]
E -->|"SHIP"| F["Merged --no-ff to main"]
E -->|"PARK"| L["PARKED in the ledger, branch reset"]
Clone and run — no package, no dependencies beyond bash, git, and an
opencode binary on PATH with a configured model:
git clone https://github.com/andrepontesmelo/archloop
cd archloopThere is no tarball release, so there is no checksum to verify — pin a tag or commit for reproducibility instead of floating on a branch:
git checkout <tag-or-commit> # pin what you run, especially overnightWarning
The loop drives sessions that implement code and run reviews in worktrees:
it never touches the canonical tree, but it executes agent-written code.
Review the target repo's .archloop/config before unattended overnight
runs — a wrong test/lint command or model id burns quota or merges surprises.
Model credentials are required in the session runner's config.
Verify the install with the zero-quota gate (no model calls, no keys needed):
bash scripts/stub-validation.sh # 25 assertions across 6 scenariosUseful commands:
bash scripts/stub-validation.sh # the local gate — run before every push
bash scripts/concurrency-gate.sh # the CI concurrency gate: two parallel suite runs
./run.sh /path/to/repo [max_items]
./archloop-loop.sh /path/to/repo [max_items] [max_rounds]# one round: scan → implement → gate → merge
./run.sh /path/to/repo [max_items]
# loop until no Strong candidates remain (or MAX_ROUNDS hit)
./archloop-loop.sh /path/to/repo [max_items] [max_rounds]
# nightly: install once — 02:17 every night, unattended
( crontab -l 2>/dev/null; echo "17 2 * * * /path/to/archloop/archloop-loop.sh /path/to/target-repo" ) | crontab -Scheduled runs are fully self-logging: the loop driver writes every round and
verdict into the target's .archloop/loop-driver.log. A systemd user timer
alternative and unattended-run notes live in docs/nightly.md.
Optional per-repo config is read from the target's .archloop/config (model overrides,
merge/push toggles, night label). Artifacts land in the target's .archloop/ — add
.archloop/ to the repo's .git/info/exclude (the loop driver does this itself if it's
missing).
Start at the docs index:
- Architecture — pipeline, pieces, verdict contract, sequence.
- Nightly runs — cron / systemd user timer install, unattended-run notes.
- Development — layout, the local gate, conventions, pre-push checklist.
PRs welcome — see CONTRIBUTING.md for the workflow and the local gate. Security issues: SECURITY.md (do not open a public issue).
- Harness-generic orchestration — today each stage is one
opencode runsession. Next step: make the runner generic across harnesses — DeepSeek, Claude Code, opencode, Codex, Hermes — so any of them can execute the stages.
- Bash and git; an
opencodebinary on PATH with a configured model.
MIT — see LICENSE.
