1---
2name: loops
3description: Design, pilot, and run standing agent loops — scheduled agents (cloud routines or local crons) that watch a system between sessions, keep its state of record honest, and escalate to a human instead of acting. Use when the user says "set up a loop", "monitor X on a schedule", "check this every few hours", "recurring agent", "routine", or wants something watched automatically between work sessions.
4---
5
6# Loops
7
8How to stand up a standing agent loop: a scheduled agent that wakes on a cadence,
9reads the state of record, checks live reality against thresholds a human already
10wrote down, records what changed, and drafts escalations for a human to act on.
11The loop is a watcher and a scribe. It is never an operator.
12
13## 0. When a loop is worth having (and when it is not)
14
15A loop earns its keep when all three are true:
16
171. **The watched system moves between your sessions.** Deadlines attached to
18 calendar dates, SLAs measured in hours, external state that changes without
19 you (deliverability rates, a queue, a ramp schedule). If state only changes
20 when you act, a loop just confirms nothing happened.
212. **The rules are already written down as numbers.** A loop enforces
22 thresholds; it must never invent them. If you cannot point at a doc that
23 says "X must stay below Y after date Z", write that doc first (the meirlabs
24 convention: a Verification section in the domain's ops skill).
253. **Catching a breach hours earlier changes the outcome.** Compliance clocks,
26 reputation damage that compounds, ramps with due dates. If nothing bad
27 happens by waiting for your next session, wait for your next session.
28
29Do not build a loop as a substitute for reading state when you start working —
30sessions still read the state of record first. And do not build one before the
31system it watches is live: a loop watching static state is a safety shakedown
32at best, noise at worst.
33
34## 1. The one archetype: watcher-scribe
35
36Every loop starts life as a watcher-scribe. It has exactly three permitted
37outputs, and a hard rule above them:
38
39**HARD RULE, stated verbatim in the prompt, no exceptions:** the loop NEVER
40performs the domain's real actions (send, launch, approve, suppress, change
41DNS or settings, spend money). If any action other than the three below seems
42required, it STOPS and escalates instead.
43
441. **Read live state** (read-only APIs, DNS, files).
452. **Update the state of record** — the domain's OPS file. Correcting drift
46 between the file and reality is the scribe's job, not an escalation.
473. **Draft escalations** for the human. Format, always: what tripped, the
48 measured number, the threshold it crossed, the suggested human action.
49 Specific and quantitative; never "something looks off".
50
51Promoting a loop from watcher to operator (letting it fix things) is a
52separate, later decision made only after a clean pilot — and even then, one
53narrow action at a time.
54
55## 2. Write the loop spec before the loop
56
57A loop is born as a spec document, not a schedule. The spec (keep it in
58`ops/tasks/<loop-name>.md`; worked example in the meirlabs homebase:
59`ops/tasks/loops-pilot-outreach.md`) carries:
60
61- **Objective** — one paragraph: what it watches, what it writes, what it never does.
62- **The exact prompt** — self-contained, because a scheduled agent starts with
63 zero context. Include the hard rule, the read order, each check with its
64 numeric threshold, and the output rules.
65- **Read order, non-negotiable:** (1) the state-of-record file, (2) the rules
66 doc with the thresholds, (3) only then live state — so the loop interprets
67 numbers against rules instead of guessing. If either file is unreadable, the
68 loop does nothing and reports that it is blind. Acting on partial state is
69 the cardinal sin.
70- **Cadence + why** — justified against how fast the watched state actually
71 moves and what the tightest real SLA is. Cold-email state moves in hours →
72 4 wakes/day. A nightly report → 1. Complement existing loops; never
73 duplicate one.
74- **Escalation conditions** — the enumerated list of "notify, do not act" cases.
75- **Pilot plan and pass/fail bar** (section 4).
76- **Prerequisites checklist** — every file, credential, and access path the
77 loop needs, each independently verified before launch.
78
79## 3. Where the loop runs (decide with eyes open)
80
81**Cloud routine** (claude.ai/code/routines, created via the /schedule skill):
82survives your machine being off. But it is a sandbox:
83- GitHub access needs the Claude GitHub App installed on the org, or a
84 `/web-setup` token sync from a CLI that can already reach the repo. Verify
85 with a throwaway run BEFORE trusting a schedule — the classic silent failure
86 is a routine whose checkout never worked.
87- No access to your machine: no Keychain, no local files, no local env.
88 Secrets go in the routine's cloud-environment variables (UI-only, stored in
89 plain text — judge accordingly) or the loop runs without them (see the
90 known-gap rule, section 5).
91- Writes default to `claude/*` branches + a PR, not pushes to main. For a
92 pilot, keep that default: it contains an over-reaching loop at the cost of
93 one merge click.
94- The loop reads `origin/main`. Local sessions must push state-of-record
95 changes promptly or every wake sees a stale file and "corrects" it backwards.
96- Cron is UTC. A local-time cadence drifts by an hour across DST changes;
97 note it in the spec.
98
99**Local schedule** (cron on your machine): full repo, Keychain, and network
100access, no sandbox friction — but wakes silently skip when the machine is off
101or asleep. Fine for loops that tolerate missed wakes; wrong for SLA clocks.
102
103**Secrets hygiene, wherever the loop runs:** any secret file on disk is `0600`,
104never `0644` — make that the default, not a per-incident fix. Better still, keep
105no long-lived plaintext secret files at all: pull on demand (`vercel env pull`),
106use a manager (1Password CLI, `direnv` with an encrypted store), or the OS
107keychain. Cloud-environment variables are stored in plain text — treat them as
108the lowest tier and put only read-only, easily-rotated keys there.
109
110## 4. Pilot protocol: prove it small, then decide
111
112Never turn a loop on wide. In order:
113
1141. **Dry run by hand.** Run the exact prompt once in a normal session with one
115 modification: propose-only — everything it would have written goes to a
116 scratch file, nothing touches the repo or any API mutably. Read the output.
117 Two questions: did it try to do anything beyond its three permitted
118 outputs, and would its writes have been correct and quiet?
1192. **Short scheduled window.** ~20 wakes (about 5 days at 4/day). Watch for the
120 two failure modes: **stalling** (a wake that produces nothing or silently
121 errors) and **over-reaching** (editing more than its files, drafting noise,
122 proposing to act).
1233. **Iterate the prompt, not the cadence, first.** Noisy → tighten the
124 no-change rule and the escalation bar. Only a loop that genuinely misses
125 fast state earns a tighter interval.
1264. **Usage review.** After the window, check cost per wake and total. A
127 read-heavy monitor should be cheap; an expensive one is over-fetching or
128 over-writing and needs trimming before it runs indefinitely.
1295. **Decide, against the pre-written bar:** promote only if zero unsafe
130 actions, at most 1 false-positive escalation, every real state change
131 reflected within one wake, and cost acceptable. Otherwise stop and
132 redesign. Widening scope or cadence is a separate later decision.
133
134## 5. Output discipline (where loops die)
135
136- **No-change wakes write nothing.** No branch, no PR, no "no change" log
137 line. A one-line session summary is enough. Loops die by noise: four
138 do-nothing PRs a day trains the human to ignore the loop, and then the real
139 escalation is ignored too.
140- **Encode known gaps explicitly.** If a credential or data source is
141 deliberately absent (a key not provisioned yet), the prompt must say so and
142 instruct the loop to skip those checks silently, noting them only in the
143 session summary. Otherwise every wake escalates "I am blind" and the pilot
144 fails on false positives through no fault of the design. Only an
145 unexpectedly failing source is real blindness worth escalating.
146- **Escalations are files, not vibes.** One dated file per escalation in an
147 agreed place the human actually looks (e.g. `<domain>/escalations/`),
148 delivered by PR, with a pointer line in the ops log. Agree on the landing
149 place before launch; it is a spec prerequisite.
150- **Absolute dates only** in everything the loop writes.
151
152## Verification
153
154Quantitative checks a session (or a meta-loop) can run against any loop built
155with this skill:
156
157- The loop's spec doc exists and contains: the hard rule verbatim, a numeric
158 threshold for every check, a cadence justification, and a pilot pass/fail
159 bar. A loop with an unwritten threshold is a fail.
160- Dry run completed before the schedule existed, with zero unsafe actions and
161 zero repo writes. No dry-run record = do not launch.
162- Every threshold the prompt cites matches the domain rules doc exactly
163 (numbers, dates, units). A drifted copy is a fail; the prompt should cite
164 the doc, not fork it.
165- Cloud checkout verified by an actual run before the first scheduled wake.
166- Pilot window defined in wakes (default 20) with the promote bar: 0 unsafe
167 actions, ≤1 false-positive escalation, every real state change reflected in
168 the state of record within one wake.
169- No-change wakes produced zero repo writes during the pilot. Any "no change"
170 commit or PR is a fail.
171- Post-pilot usage review done before the loop runs past its window.
172