Em dashes (—) and en dashes (–) had spread across comments, docs, tests, and a few UI strings, reading as AI-generated boilerplate rather than house style. Replaced each with punctuation matching its context: colon for explanatory clauses, comma for asides, plain hyphen for numeric/legal ranges (e.g. "21-23§"), "to"/"till" for date ranges, parentheses for paired-dash asides. messages/en.json and messages/sv.json were fixed by hand together to keep sv/en in sync. Left untouched where the dash is the functional subject rather than decorative punctuation: date-range-parser.ts's separator regex, charset-repair.ts's CP1252 byte-mapping table (and its test), the SIE encoding mojibake docs, generic-csv.ts's minus-sign normalizer, the agent system-prompt files that already instruct against em dashes, and a golden iXBRL test fixture compared byte-for-byte. Also fixes two bugs surfaced along the way: an off-by-one in ApiKeysPanel's scope-label split (a leftover from an earlier partial pass), and a charset-repair test that had lost the literal en-dash it exists to verify. Regenerated the agent atom seed migration (skills:generate) since 27 SKILL.md files changed. Added a CLAUDE.md rule against em/en dashes, with an explicit carve-out for the functional-dash cases above. Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
5.8 KiB
Agentic Loops: Playbook
Proactive loops that scan the codebase and our external systems (GitHub, Vercel), then
propose fixes and file well-formed tickets. This file is the shared contract every loop obeys.
Skills under .claude/skills/loop-* implement the loops; cloud routines and local /loop invocations
run them on a schedule.
These are proactive loops: triggered by a schedule, no human in real time, each item exits when its goal is met. Quality comes from the system around the loop (verification skills, clean conventions, second-agent review), not from a clever prompt.
This file lives at
.claude/loops.md(committed).dev_docs/*is gitignored ("internal reference, not published"), so the playbook cannot live there: the cloud routines clonemainand need this file present.
Autonomy policy: "Propose, don't merge"
This is a Swedish accounting/compliance codebase. Loops never touch main or production.
| Loop may… | Loop may NOT… |
|---|---|
Fix trivial/low-risk issues on a loop/* branch |
Merge any PR (gh pr merge is forbidden) |
| Open PRs for review, comment on PRs | Push to main or any human's active branch |
| File / label / dedupe / close GitHub issues | Force-push over another author's commits |
| Push to a PR branch it created, or a dependabot branch | Edit posted journal entries / violate an Accounting Guard Rail |
Escalate to a human via loop:needs-human |
Act on PRs from contributor:flagged / pr:flagged authors |
Every code change a loop makes must pass the loop-verify gate before
the PR is opened. No exceptions.
Ticketing & dedupe conventions (all loops share these)
Destination: GitHub Issues + PRs in erp-mafia/accounted (via gh). Not Linear.
Labels: loop:auto (always, on anything a loop creates), loop:vercel, loop:triage,
loop:design, loop:needs-human (a loop tried and could not safely proceed).
Idempotency / anti-spam: MANDATORY. Before filing anything:
- Compute a stable fingerprint (error signature, file:line, rule id, never a timestamp).
gh issue list --search "<fingerprint> in:body state:all"(include closed). Match → comment instead of filing a duplicate; closed + recurring → reopen with a note.- Embed
<!-- loop-fingerprint: <hash> -->in the body so future runs find it.
Branch naming: loop/<loop>-<ref>, e.g. loop/ci-pr848, loop/issue-843, loop/vercel-<hash>.
Anti-thrash: if the same fix (same fingerprint) already failed, stop, label loop:needs-human,
comment what was tried. Never retry the same failing action in a cycle.
Per-run caps (cost): each run bounds how much it acts and log()s what it skipped. Defaults below.
The loops
| # | Loop | Skill | Where | Cadence (default) | Per-run cap |
|---|---|---|---|---|---|
| 1 | PR + CI triage | loop-pr-ci-triage |
Cloud trig_01J2nG7eB9gsdAb9YSGBVwa8 |
0 7,11,15 * * * UTC |
≤5 PRs |
| 2 | Vercel errors → tickets | loop-vercel-errors |
Local (Vercel MCP); cloud needs VERCEL_TOKEN. Trigger trig_014CmE3gTJ7ErnvL2trPYymu disabled |
on-demand / /loop |
≤8 issues, ≤2 PRs |
| 3 | Issue triage + easy-fix | loop-issue-triage |
Cloud trig_017hB94ieGVwreJqHpGRDVoM |
0 7,15 * * * UTC |
triage all; ≤2 PRs |
| 4 | UI/UX + design scan | loop-design-scan |
Local (/loop) |
on-demand | ≤1 area, ≤6 findings |
Loops 1 & 3 are cloud routines (only need gh). Loop 2 (Vercel errors) is local: the Vercel MCP is
only available locally, and there's no error-aggregation service (Sentry is not used). Loop 4 is
local: it needs npm run dev + Chrome to render/screenshot the UI.
The verification gate (loop-verify)
Before any loop opens a PR: check:lint → targeted vitest → test:pg iff a
trigger/RPC/RLS/migration was touched → check:guards → the "no core imports from @/extensions/"
grep → build if config/types changed. Plus: never violate an
Accounting Guard Rail; keep sv/en in sync (i18n).
Cloud-environment requirements (verify these: they are the usual failure points)
Cloud routines run in a fresh session in the anthropic_cloud env (env_01R1K99XTZCEptnQ7k955qfN),
cloning main. For them to work:
ghmust be authenticated in the cloud env. Each routine's preflight stops and reports "environment not provisioned" if not. Verify via the completion notification of the first fire.- Cloud routines cannot reach interactively-authenticated MCPs (Vercel/Supabase plugins are not in
the routine tool allowlist). Loops rely on
gh(via Bash) + HTTP APIs. - The Vercel-errors loop runs locally (Vercel MCP). Sentry is not used in this codebase: the
SENTRY_*names in.env.local/CLAUDE.md are leftovers. To run this loop in the cloud instead, set aVERCEL_TOKENsecret on the env and accept that Vercel runtime-log retention is short (recent window only).GH_TOKENis the one secret loops 1 & 3 actually require (private-repo access; OAuth-only integration does not work for private repos, anthropics/claude-code#64130).
Operating the loops
- List / pause / retune:
/schedule(or the trigger MCP tools;update_triggerfor a new cron). - Run on-demand:
/loop-pr-ci-triage,/loop-issue-triage,/loop-vercel-errors,/loop-design-scan <area>. Wrap in/loop <interval>to repeat locally;/goalfor a hard exit. - Cost: route mechanical steps to cheaper models; reserve judgment for the strong model.
/usage. Don't run more often than the watched thing changes.
Extending
When a loop produces a bad result, encode the lesson back into the skill / a CLAUDE.md rule / a verifier so every future run improves: don't just fix the one output.