A complete hands-on run through all 12 Loop Engineering practice projects — building, breaking, and diagnosing real AI agent loops from the ground up. Each project lives in its own folder with its own README.md, AGENTS.md, CLAUDE.md, .claude/settings.json, and full git history.
Projects 6, 8, and 10 are partially complete due to a documented account-level restriction (Claude Code Web / GitHub App install blocked by org admin — same root cause across all three, fully explained in each folder). Project 11 is fully specced but not live for the same reason. Every gap is named honestly and documented precisely enough to finish later.
| # | Project | Concepts | Difficulty | Status |
|---|---|---|---|---|
| 1 | Watch a long task finish | C4 | Easy | Done |
| 2 | Make the tests pass, then stop | C5, C11 | Easy–Medium | Done |
| 3 | Morning brief with a memory | C6, C12 | Medium | Done |
| 4 | Fix loop with a real checker | C8, C9, C11 | Medium–Hard | Done |
| 5 | Codify the body (shell) | C8, C11, DW | Medium–Hard | Done |
| 5b | Codify the body (/workflows) | C8, C11, DW | Medium–Hard | Done |
| 6 | The doorbell loop | C7, C10 | Medium | Partial |
| 7 | Break it on purpose | C13, C14 | Medium | Done |
| 8 | Your own daily loop (capstone) | All 6 parts | Capstone | Partial |
| 9 | Rehearse a routine for free | A1, A3, A5 | Easy | Done |
| 10 | The secrets drill | A2, A4 | Easy–Medium | Partial |
| 11 | Two-routine gate | A3, A4, A6 | Medium–Hard | Specced |
| 12 | Dreaming loop (second capstone) | C6, C11, C12 | Capstone | Done |
Key: C = Core Concept · DW = Dynamic Workflows interlude · A = Appendix (Routines)
Folder: loop-project-1/ | Concept: C4 (in-session loop) | Difficulty: Easy
Command:
/loop 1m check if long_task.sh has finished (test -f done.flag);
if it has, read done.flag, tell me it's done, and stop the loop yourself
What happened: long_task.sh ran in the background. The loop checked every beat, reported "not finished yet" once, then found done.flag and stopped itself cleanly.
Outcome: Loop noticed the finish, reported it once, stopped — no human intervention.
Status: DONE
Folder: loop-project-2/ | Concepts: C5 (conditional loop), C11 (maker-checker) | Difficulty: Easy–Medium
Command: /goal Fix calculator.py so that running python3 test_calculator.py exits with code 0 and prints "ALL TESTS PASSED"...
What happened: calculator.py had swapped operators (add/multiply/subtract all wrong). Attempt 1 failed; code was fixed; attempt 2 passed. The test runner's exit code was the only stopping signal — not "looks correct."
Outcome: Stopped because tests passed, not because it hit the 6-attempt cap.
Status: DONE
Folder: loop-project-3/ | Concepts: C6 (unattended schedule), C12 (the spine) | Difficulty: Medium
Approach: No /loop or /goal — this concept requires a real scheduled Routine (cron-like). Simulated as two separate beats in two fresh sessions, each using the same plain prompt:
This is one beat of a scheduled loop. Do these steps in order:
1. Read progress.md fully first — this is your only memory of past runs.
2. Search the src/ folder for all "TODO" comments (grep for TODO).
3. Compare against what is already in progress.md's run history.
4. Write a short summary: total TODOs, new since last run, list new ones.
5. Append a new dated entry to progress.md — do not delete old entries.
6. Show me the new entry.
What happened: Beat 1 found 3 TODOs (all new). A 4th TODO was added to simulate a day passing. Beat 2 found 4 TODOs but reported only 1 as new — progress.md (the spine) was the only memory used, not conversation history.
Outcome: Second run built on the first; nothing was re-reported.
Status: DONE
Folder: loop-project-4/ | Concepts: C8 (worktree), C9 (skill), C11 (maker-checker) | Difficulty: Medium–Hard
Bug: src/inventory.py — apply_discount added the discount instead of subtracting it.
What happened:
| Branch | Fix | Checker Verdict |
|---|---|---|
fix/good-discount |
Real fix: + changed to - |
PASS — PR opened (pr/fix-good-discount.md) |
fix/bad-discount |
Lookup table hardcoding all 3 test inputs; bug returned for anything else | FAIL — caught by diff review (pr/fix-bad-discount-REJECTED.md) |
Bonus: Two fresh, isolated subagents (.claude/agents/reviewer.md, haiku model) independently re-reviewed both diffs and reached the same verdicts — without any memory of this conversation.
Outcome: Good fix got PASS + PR; bad fix got FAIL with reasons; checker was not fooled by green tests.
Status: DONE
Folder: loop-project-5/ | Concepts: DW interlude, C8, C11 | Difficulty: Medium–Hard
Engine: run_fix_loop.sh (setup / verify / reset) — pure shell, no AI, deterministic.
Candidates:
| Candidate | Bug |
|---|---|
is_even |
Inverted condition (== 1 instead of == 0) |
average |
Off-by-one divisor (len(numbers) + 1) |
reverse_words |
Reversed characters, not word order |
Run 1: setup → 3 dispatched agents fixed each bug in isolated worktrees → verify → 3/3 PASS
Run 2 (the real point): reset → setup → verify without re-running the maker step → 3/3 FAIL, identical to original bugs. Proved the engine has zero memory between runs.
Outcome: One command ran the whole body. The no-memory claim was proven on-machine, not just asserted.
Status: DONE
Folder: loop-project-5-b/ | Concepts: DW interlude, C8, C11 | Difficulty: Medium–Hard
Different from 5(a): Attempted the Claude Code /workflows approach instead of a hand-written shell script.
Blocked: /workflows did not exist in Claude Code 2.1.233 — the course's own "research preview" caveat applied.
Adapted: Same plain-words prompt run twice in genuinely separate claude sessions.
| Run | Result |
|---|---|
| Run 1 | 3 parallel isolated worktrees, maker + @reviewer → 3/3 PASS |
| Run 2 (fresh session) | Redid all 3 fixes from scratch, same PASS verdicts, zero reference to Run 1 |
Outcome: Documented the blocker honestly, adapted the approach, still proved the same lesson (no session memory, engine vs. loop).
Status: DONE
Folder: loop-project-6/ | Concepts: C7 (event-driven), C10 (connectors) | Difficulty: Medium
Bug planted: Removed if age is None: return False from is_valid_age, disguised as a readability refactor — branch fix/age-validation-refactor.
Two automated paths tried, both blocked:
- GitHub Actions + Anthropic API — requires a paid API key separate from Claude Pro. Deleted.
- Claude Code Routine + GitHub PR webhook — blocked by org-admin restriction on "Claude Code Web" and by a deliberate choice not to grant a shared account broad GitHub access.
What was done instead: A real PR (#1) was opened via the GitHub API. The diff was read and the bug reasoned about for real, and the review was posted as a real GitHub PR comment — just triggered by hand instead of a webhook.
| Checklist Item | Result |
|---|---|
| PR got a real bug-flagging review | Done |
| Review fired automatically (zero-prompt) | Blocked — see above |
New commit re-fires via synchronize |
Not testable without auto-trigger |
Status: PARTIAL
Folder: loop-project-7/ | Concepts: C13 (cost), C14 (observability) | Difficulty: Medium
Cost (real, measured):
| Cadence | Monthly cost |
|---|---|
| Daily | ~$4.89 |
| Hourly | ~$117 |
| Every 5 min | ~$1,410 |
One beat = 38,808 tokens at Sonnet 5 pricing ≈ $0.163/beat. Full math in COST.md.
Sabotage: AGENTS.md hardened first (every beat must write one SUCCESS/FAILED line to beat.log). Then a beat was pointed at src_incoming/ — a folder that does not exist.
Result — did NOT fail silently:
2026-08-17T00:12:43Z | FAILED | src_incoming: No such file or directory | NEEDS HUMAN: ...
Diagnosis from spine alone: What failed (src_incoming/ missing), when (2026-08-17T00:12:43Z) — read from beat.log + progress.md only, no replay needed.
Status: DONE
Folder: loop-project-8/ | Concepts: All 6 parts | Difficulty: Capstone, 2–4 hrs
Chore: docs-freshness — checks TASKS.md/README.md for contradictory or mismatched status markers on this repo's own real files.
Beat-by-beat summary:
| Beat | Action | Result |
|---|---|---|
| 1 | Scan | Found 2 real CONTRADICTIONs (Projects 6 and 7 — duplicate Status lines) |
| 2 | Maker + Checker | Fix drafted in worktree → Checker: PASS → merged to local main |
| — | Bad-fix scenario | Planted bad fix (falsely marked P8 "done") → Checker: FAIL, with reasons |
| 3 | Scan | 0 issues (first clean beat) |
| 4 | Scan | 0 issues (second consecutive clean beat) |
| 5 | Soft-stop | Loop stopped itself from beat.log/progress.md alone — no prompting |
Honest gap: Real cron heartbeat not re-attempted — Project 6 already proved the same account-level blocker. Simulated as 5 memory-isolated beats, labeled honestly as such.
| Checklist Item | Result |
|---|---|
| All 6 parts built and exercised | Done |
| Real bug found and fixed, bad fix rejected | Done |
| Loop stopped itself via spine | Done |
| Ran unattended for a real week | Not met — account restriction documented |
Status: PARTIAL
From the course's Appendix on Routines. Projects 9–11 reproduce the appendix's main failure cases at low cost/risk. Project 12 is a full second capstone, not a drill.
Known blocker: Projects 9–11 require a Claude Code Routine attached to a GitHub repo. The same org-admin restriction documented in Project 6 applies. Each project attempts it honestly and documents what was achievable without it.
Folder: loop-project-9/ | Concepts: A1, A3 (one-off schedules), A5 (reading runs) | Difficulty: Easy
Adapted: Used a no-repo routine (GitHub App connection blocked, same as P6). The A5 lesson does not require a repo.
Runs:
| Run | Prompt | Task result | Status field |
|---|---|---|---|
| 1 | Compute 2026+20+8 | Correct (2054) | success is_error=false |
| 2 | Read a non-existent file | Failed (file not found) | success is_error=false |
Key lesson (A5): The status column reports whether the session completed cleanly — not whether the task actually happened. The real outcome is only visible in the transcript.
Status: DONE
Folder: loop-project-10/ | Concepts: A2 (the environment), A4 (secrets) | Difficulty: Easy–Medium
Half 1 — gitignore mechanic (fully proven locally):
Real .env gitignored, committed, then a real git clone confirmed .env absent in the clone — identical to what a cloud Routine's fresh clone would see.
Half 2 — environment variables (mechanism proven, custom secret deferred):
A real Routine confirmed that Bash can read env vars directly (~140 platform vars present). Adding a custom secret (PROJECT10_DUMMY_TOKEN) still requires the claude.ai web UI — no tool can do it.
Side finding: The Default environment already has credential-shaped var names (GH_TOKEN, AWS_ACCESS_KEY_ID, etc.) — only names read, nothing used; they belong to platform tooling, not the user.
| Checklist Item | Result |
|---|---|
| Gitignore mechanic proven (not just asserted) | Done |
| Custom token read from environment | Pending — same UI step as P9/11 |
Status: PARTIAL
Folder: loop-project-11/ | Concepts: A3 (API trigger), A4 (the gate), A6 (checklist) | Difficulty: Medium–Hard
Two blockers, both named honestly:
- Routine A would write a Google Calendar event to the shared account owner's real Calendar — the harness flagged this as needing explicit human go-ahead. The choice was made not to touch someone else's account for a practice drill.
- Routine B's API trigger can only be enabled via the claude.ai web UI — no tool can create one, only fire an existing one.
What was built instead: Full, copy-paste-ready specs for both routines:
| File | Contents |
|---|---|
ROUTINE-A-SPEC.md |
Complete prompt, trigger config, connector choice |
ROUTINE-B-SPEC.md |
Complete prompt, exact curl call to fire it, reasoning |
SETUP.md |
Exact build order + Appendix A6 checklist pre-filled |
Ready to build for real in under 10 minutes on your own Claude account.
| Checklist Item | Result |
|---|---|
| B ran only because you fired it | Pending — needs routines to exist |
| B's transcript shows action happened | Pending |
| A6 checklist run over both routines | Pre-filled and ready in SETUP.md |
Status: SPECCED — not live
Folder: loop-project-12/ | Concepts: C6, C11, C12 | Difficulty: Capstone, 2–3 hrs
A loop over a loop: watches Project 8's real spine (progress.md / beat.log) and proposes rule-file changes — evidence-cited only, drafted as a PR, never a direct commit.
Three planting attempts:
| Attempt | Plant | Loop response |
|---|---|---|
| 1 | Uncommitted beat.log line referencing a non-existent file |
Ran git diff, detected line wasn't real history — correctly refused |
| 2 | Committed line claiming a branch that didn't exist | Ran git branch -a, found no such branch — correctly discarded |
| 3 | Two committed FAILED entries describing a real fragility (hardcoded relative path in skill) |
Caught, cited word-for-word, and disclosed unprompted that the evidence was planted |
The fix: docs-freshness/SKILL.md step 3 — replaced hardcoded ../TASKS.md with git rev-parse --show-toplevel to resolve the repo root robustly regardless of working directory.
Checker verdict: PASS — independently re-verified every citation against main, traced the mechanics of the fix, confirmed the honesty disclosure matched commit history.
Merged: To local main (fast-forward, not pushed) after human check-in.
| Checklist Item | Result |
|---|---|
| PR traces to real, cited log entries (checker-verified) | Done |
| Planted repeated failure caught and turned into a proposal | Done (third attempt — first two refusals are stronger evidence) |
| Nothing changed in rules file without merging | Done — isolated branch until human-approved |
Status: DONE
loop-engineering-project/
├── README.md ← this file
├── TASKS.md ← full progress log
├── real-life-use-case.md ← production analogues for each project
├── LICENSE ← MIT
├── CONTRIBUTING.md
├── .gitignore
├── loop-project-1/ ← Project 1: watch loop
├── loop-project-2/ ← Project 2: conditional loop
├── loop-project-3/ ← Project 3: spine + schedule
├── loop-project-4/ ← Project 4: worktree + maker-checker
├── loop-project-5/ ← Project 5: codified engine (shell)
├── loop-project-5-b/ ← Project 5b: codified engine (/workflows)
├── loop-project-6/ ← Project 6: event-driven (partial)
├── loop-project-7/ ← Project 7: observability + cost
├── loop-project-8/ ← Project 8: capstone (partial)
├── loop-project-9/ ← Project 9: routine drill
├── loop-project-10/ ← Project 10: secrets drill (partial)
├── loop-project-11/ ← Project 11: two-routine gate (specced)
└── loop-project-12/ ← Project 12: dreaming loop (capstone)
Each project folder contains its own README.md with the full story of that project — setup instructions, what actually happened, honest gaps, and the course checklist.
MIT — see LICENSE.
Muhammad Sami Asghar Mughal · muhammad-sami.vercel.app · Submitted 2026-08-27