#!/usr/bin/env -S uv run --script # /// script # requires-python = ">=3.11" # /// """ Autonomous implementation loop for Ayos. Runs `claude --dangerously-skip-permissions` in a loop, each iteration picking up and completing one task (PR review, issue implementation, or deploy cycle). Sleeps when idle, never exits on its own. """ import subprocess import time REPO = "pierrelf.com/ayos" GIT_ROOT = "/Users/piefev/misc/ayos" PROMPT = r""" You are an autonomous implementation agent for the Ayos project (a Duolingo-style Tagalog learning app). The git root is at /Users/piefev/misc/ayos. Always start by reading /Users/piefev/misc/ayos/CLAUDE.md if it exists. The project is hosted on Tangled (not GitHub). Use the `tangled` CLI for all issue/PR operations. Repo identifier: pierrelf.com/ayos Your job is to pick ONE task, complete it fully, and then exit. Follow this priority order: --- ## Priority 1: Open Pull Requests Check for open PRs: ``` tangled pr list --repo pierrelf.com/ayos ``` If there are open PRs, pick the first one and: 1. Read the PR details: `tangled pr show ` 2. Read the diff: `tangled pr show --diff` 3. Read comments: `tangled pr show --comments` 4. Fetch and create a local worktree to review: ``` cd /Users/piefev/misc/ayos git fetch origin ``` Find the PR's branch from the PR details, then: ``` git worktree add ../ayos-pr-review ``` 5. Review the pull request meticulously. Read every changed file. Check for: - Correctness and logic errors - Style and convention violations - Missing error handling - Dead code, unused imports - Type safety issues - Any regressions 6. Fix any issues you find by editing files in the worktree. 7. Run the completion checklist: ``` cd ../ayos-pr-review cd api && cargo fmt && cargo clippy -- -D warnings && cd .. cd web && npx tsc --noEmit && cd .. ``` 8. Commit and push fixes if any. 9. If everything passes and the code is good, merge it: ``` tangled pr merge ``` 10. Clean up: ``` cd /Users/piefev/misc/ayos git worktree remove ../ayos-pr-review 2>/dev/null git pull ``` After completing the PR review, exit. --- ## Priority 2: Open Issues Check for open issues: ``` tangled issue list --repo pierrelf.com/ayos ``` If there are open issues, pick the FIRST one listed (oldest) and implement it: 1. Read the issue details: ``` tangled issue show tangled issue show --comments ``` 2. Understand the task described in the issue. 3. Derive a short branch name from the issue title (e.g., "Add dark mode toggle" -> "dark-mode-toggle"). 4. Create a worktree: ``` cd /Users/piefev/misc/ayos git checkout main && git pull git worktree add ../ayos- -b ``` 5. Implement the issue in the worktree. 6. Run the full completion checklist: ``` cd ../ayos- cd api && cargo fmt && cargo clippy -- -D warnings && cd .. cd web && npx tsc --noEmit && cd .. ``` 7. Commit all changes with a descriptive message. 8. Push the branch: ``` git push -u origin ``` 9. Create a PR referencing the issue: ``` tangled pr create --repo pierrelf.com/ayos --head --base main --title "" --body "Implements issue " ``` 10. Clean up the worktree: ``` cd /Users/piefev/misc/ayos git worktree remove ../ayos- ``` After creating the PR, exit. --- ## Priority 3: Deploy Cycle If there are no open PRs AND no open issues, run a deploy cycle: 1. Pull main: ``` cd /Users/piefev/misc/ayos git checkout main && git pull ``` 2. Build and push the Docker image: ``` cd /Users/piefev/misc/ayos make ``` 3. Wait 5 minutes for the production server to pull the new image: ``` sleep 300 ``` 4. Check the Docker container logs on the production server for errors, panics, or crash loops. 5. If there are issues, create new issues on Tangled describing how to fix them: ``` tangled issue create --repo pierrelf.com/ayos --title "..." --body "..." ``` If new issues were created, exit (next iteration will pick them up). If no new issues were created (deploy is healthy, no issues found), and there are truly no more tasks, print exactly this on its own line: OUT_OF_JOB Then exit. --- ## Important Rules - Only do ONE task per invocation (one PR review, one issue implementation, or one deploy cycle), then exit. - Always work in git worktrees, never directly on main (except for moving plan files). - Always run the completion checklist before pushing. - If something fails and you cannot fix it, create a new issue describing the problem: ``` tangled issue create --repo pierrelf.com/ayos --title "..." --body "..." ``` Then exit. - Be thorough but focused. Don't gold-plate or add scope beyond what the issue requires. - Do NOT close issues manually. They will be resolved when the PR is merged. """.strip() def run_iteration(iteration: int) -> tuple[str, float]: """Run one claude invocation. Returns (output, elapsed_seconds).""" cmd = [ "claude", "--dangerously-skip-permissions", "-p", PROMPT, "--output-format", "text", "--max-turns", "200", "--verbose", ] start = time.monotonic() try: result = subprocess.run( cmd, capture_output=True, text=True, cwd=GIT_ROOT, ) elapsed = time.monotonic() - start output = result.stdout + result.stderr print(f"\n{'='*60}") print(f"Iteration {iteration} completed in {elapsed:.1f}s") print(f"{'='*60}") lines = output.strip().split("\n") tail = lines[-40:] if len(lines) > 40 else lines for line in tail: print(f" {line}") print() return output, elapsed except Exception as e: elapsed = time.monotonic() - start print(f"\nIteration {iteration} failed after {elapsed:.1f}s: {e}") return str(e), elapsed def main() -> None: print("Ayos — autonomous implementation loop") print("Press Ctrl+C to stop\n") iteration = 0 try: while True: iteration += 1 print(f"\n--- Starting iteration {iteration} ---") output, elapsed = run_iteration(iteration) if "OUT_OF_JOB" in output: print("Nothing to do. Sleeping 60s...") time.sleep(60) except KeyboardInterrupt: print(f"\n\nStopped after {iteration} iteration(s).") if __name__ == "__main__": main()