Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,29 @@ All notable changes to Looper are documented here. Versions follow
[Semantic Versioning](https://semver.org/); the loop spec format is versioned
separately via `version:` in `loop.yaml` (currently `1`).

## Unreleased

### Added — `looper lint`
- `looper.py lint <loop.yaml>` — the design rubrics as a static checker, no
wizard required. Compiles the spec first (compile rejections exit 2), then
reports findings in two severities: **errors** for specs that will not
behave the way they read at runtime (`judge-criterion-unreachable` — judge
criteria on a `fixed_passes` gate are never evaluated; `unscoped-egress` —
a gate-referenced cross-vendor member with no `privacy.egress` declaration;
`egress-unknown-member` — an egress entry naming nobody) and **warnings**
for rubric coaching (`all-vibe-verification`, `no-verification-criteria`,
`same-family-judge`, `delivery-gate-no-programmatic`,
`non-local-member-without-egress`, `egress-consent-pregranted`,
`unreferenced-council-member`, `unhonored-human-checkpoint`,
`missing-max-revisions`, `no-wall-clock-cap`, `no-stop-conditions`,
`shell-string-check`, `unresolved-placeholders`). Exit 1 on errors, or on
any finding with `--strict`; `--json` emits machine-readable findings for
CI (exit 2 compile failures print to stderr, no JSON).
- The wizard now runs `lint` after every compile and treats errors as
blockers, warnings as coaching to relay (SKILL.md step 10).
- 10 new tests (37 total), including a sweep asserting all five shipped
templates and the example lint with zero errors.

## 0.3.0 — 2026-07-05

### Added — loop pattern library
Expand Down
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,25 @@ what's installed, and still runs its full critique, privacy, and preview flow
before emitting. See [`templates/loops/`](templates/loops/) for the catalog
and per-template docs — including how to add your own.

### Lint any loop.yaml

The design rubrics also exist as a static checker — no wizard, no interview:

```bash
python scripts/looper.py lint path/to/loop.yaml
```

`lint` compiles the spec, then checks it for the anti-patterns the rubrics
coach against: all-vibe verification (no programmatic checks), judge criteria
a runner would never evaluate, undeclared cross-vendor egress, a judge that
shares the host's model family, missing caps, and unresolved `{{PLACEHOLDER}}`
tokens. **Errors** mean the spec won't behave the way it reads (exit 1);
**warnings** are design coaching (exit 0, or exit 1 with `--strict`). A spec
that doesn't compile exits 2 with the compile error on stderr — in that case
`--json` emits nothing, so CI wrappers should check the exit code before
parsing. Add `--json` for tooling, and wire `lint --strict` into CI to gate
loop specs in PRs the same way you lint code.

### Easy: run in the same session

The default path is to let Looper continue in the same conversation. It follows
Expand Down
7 changes: 7 additions & 0 deletions SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ advanced external runner.
10. After writing `loop.yaml`, resolve the helper Python (see Helper Python
below) and run:
`"$LOOPER_PYTHON" ${CLAUDE_SKILL_DIR}/scripts/looper.py compile <target>/loop.yaml --out <target>/loop.resolved.json --render <target>/LOOP.md --session-prompt <target>/RUN_IN_SESSION.md`
Then run
`"$LOOPER_PYTHON" ${CLAUDE_SKILL_DIR}/scripts/looper.py lint <target>/loop.yaml`
and relay the findings: fix any `error[...]` before continuing (the spec
would not behave as written), and surface `warning[...]` lines to the user
as design coaching they may accept or address.
11. Ask whether the user wants to run the loop now in this session. If yes,
follow `RUN_IN_SESSION.md` directly as the active task. If no, explain that
the same file is the easy restart path and `run-loop.py` is available for
Expand Down Expand Up @@ -148,6 +153,8 @@ same shell invocation:
`"$LOOPER_PYTHON" ${CLAUDE_SKILL_DIR}/scripts/looper.py register-model <id> --invoke "<cmd> [args...]"`
- Compile and render:
`"$LOOPER_PYTHON" ${CLAUDE_SKILL_DIR}/scripts/looper.py compile <target>/loop.yaml --out <target>/loop.resolved.json --render <target>/LOOP.md --session-prompt <target>/RUN_IN_SESSION.md`
- Lint against the design-rubric anti-patterns (add `--strict` to fail on warnings, `--json` for tooling):
`"$LOOPER_PYTHON" ${CLAUDE_SKILL_DIR}/scripts/looper.py lint <target>/loop.yaml`
- Render only the in-session handoff:
`"$LOOPER_PYTHON" ${CLAUDE_SKILL_DIR}/scripts/looper.py session-prompt <target>/loop.resolved.json --out <target>/RUN_IN_SESSION.md`

Expand Down
Loading
Loading