@loop-lang/loop 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/AGENTS.md +53 -3
- package/assets/skill/SKILL.md +71 -4
- package/package.json +3 -2
- package/src/cli.mjs +5 -5
- package/src/init.mjs +1 -0
- package/src/postinstall.mjs +33 -0
package/assets/AGENTS.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
# AGENTS.md — authoring
|
|
1
|
+
# AGENTS.md — authoring LoopFlow (`.loop`) flows
|
|
2
2
|
|
|
3
3
|
This file teaches an AI assistant (Claude Code, Copilot, Cursor, etc.) how to write
|
|
4
|
-
**
|
|
4
|
+
**LoopFlow** flows. When a user asks you to design a staged, self-correcting, or human-gated
|
|
5
5
|
coding workflow — "set up a loop to fix X", "turn this epic into a pipeline", "automate
|
|
6
6
|
this multi-step task" — author a `.loop` file using the grammar below, then let the user
|
|
7
7
|
run it with `loop-run run file.loop`.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
LoopFlow is a small natural-language DSL. A `.loop` file describes the *movement* of an AI
|
|
10
10
|
coding loop: its objective, the context it may read, the actions it's allowed, how it
|
|
11
11
|
verifies itself, when it stops, and where a human steps in. The five knobs —
|
|
12
12
|
**objective, context, actions, verification, stopping rules** — are first-class instead
|
|
@@ -19,6 +19,16 @@ bug fixes with a test, refactors gated by a check, an epic broken into stories,
|
|
|
19
19
|
migration with a verification step. Don't write one for a one-off question or a trivial
|
|
20
20
|
edit — just do those directly.
|
|
21
21
|
|
|
22
|
+
Before building a loop, run the four-condition test — build one only when all four hold:
|
|
23
|
+
|
|
24
|
+
1. **Does the task repeat?** A one-time task is just a normal prompt.
|
|
25
|
+
2. **Is there a clear definition of "done"?** You must be able to verify completion — a
|
|
26
|
+
`done when` predicate (a test, a command, or a review skill). No check, no loop.
|
|
27
|
+
3. **Can you afford the iterations?** A loop re-prompts itself until done; that costs tokens.
|
|
28
|
+
Keep the `done when` check fast and add an `after N tries` thrash guard.
|
|
29
|
+
4. **Does the loop have the tools to verify itself?** It needs a way to implement *and* check
|
|
30
|
+
its own work — the predicate command or the review skill must actually be runnable.
|
|
31
|
+
|
|
22
32
|
**Interview the user before writing it.** Walk the five decisions, asking the
|
|
23
33
|
high-leverage questions and offering defaults for the rest: (1) the **goal**;
|
|
24
34
|
(2) the **`done when`** check (test / command / scan finds-nothing / human);
|
|
@@ -48,6 +58,8 @@ look at: <files>, and the last failure context the agent reads before acting (
|
|
|
48
58
|
allow edits automatically, but ask me before <classes> action policy
|
|
49
59
|
each cycle: plan, then act, then observe the repeated steps (any subset, in order)
|
|
50
60
|
also: <pass>, <pass> extra finishing passes run after the goal is met
|
|
61
|
+
use skills: <a>, <b> named skills the loop may invoke during plan/act
|
|
62
|
+
remember in "<file.md>" cross-run memory: read lessons on start, append an outcome on stop
|
|
51
63
|
reflect turn a failure into context for the next plan (the back-edge)
|
|
52
64
|
|
|
53
65
|
when it passes and the goal is met: stop
|
|
@@ -72,11 +84,49 @@ done when the test "billing.spec.ts::apostrophe" passes # a named test
|
|
|
72
84
|
done when "pnpm test" passes # a shell command, exit 0
|
|
73
85
|
done when "semgrep --severity=high" finds nothing # a shell command, empty output
|
|
74
86
|
done when a human confirms "looks right at 375px" # a human check
|
|
87
|
+
done when the skill "email-review" approves # a review skill: approved / not
|
|
88
|
+
done when the skill "email-review" scores 8 or more # a review skill: numeric threshold
|
|
75
89
|
```
|
|
76
90
|
|
|
77
91
|
The command in a predicate runs in the user's shell with their privileges (like an npm
|
|
78
92
|
script). It IS meant to be a real command. Prefer a fast, deterministic check.
|
|
79
93
|
|
|
94
|
+
The **skill** predicate bridges an abstract goal to a verifiable one: when "done" isn't a
|
|
95
|
+
test or a command (a good email, a sound design), have a review skill return an
|
|
96
|
+
approved/rejected verdict or a numeric score. Build that review skill manually first and
|
|
97
|
+
confirm it judges well, then wire it in as the loop's check.
|
|
98
|
+
|
|
99
|
+
### `use skills` — coordinate proven skills
|
|
100
|
+
|
|
101
|
+
Instead of one giant prompt, a loop can name skills it may call while planning and acting:
|
|
102
|
+
|
|
103
|
+
```loop
|
|
104
|
+
loop "decide whether to cancel the morning run":
|
|
105
|
+
goal: a clear go / no-go call the runner trusts
|
|
106
|
+
use skills: check-weather, analyze-workout
|
|
107
|
+
done when the skill "workout-review" approves
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
This is **skill-driven development**: build and battle-test each skill on its own first,
|
|
111
|
+
then have the loop coordinate them. Don't invent a loop around skills that don't exist yet —
|
|
112
|
+
prove the skill manually, then wire it in (as an execution skill via `use skills:`, or as a
|
|
113
|
+
verifier via `done when the skill "…" approves`). See `examples/skills_memory.loop`.
|
|
114
|
+
|
|
115
|
+
### `remember in` — cross-run memory
|
|
116
|
+
|
|
117
|
+
A loop forgets everything between runs unless you give it a memory file. `remember in` makes
|
|
118
|
+
the loop read the file's lessons into its first plan and append a dated outcome entry when it
|
|
119
|
+
stops — so it improves run over run instead of repeating mistakes.
|
|
120
|
+
|
|
121
|
+
```loop
|
|
122
|
+
loop "...":
|
|
123
|
+
goal: ...
|
|
124
|
+
remember in "morning-run.memory.md"
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
`reflect` is *within-run* memory (a failure feeds the next plan); `remember` is its
|
|
128
|
+
*across-run* counterpart. The file is plain markdown — readable and editable by a human.
|
|
129
|
+
|
|
80
130
|
### `flow` — chaining loops across files
|
|
81
131
|
|
|
82
132
|
A `flow` sequences multiple `.loop` files. Each step runs the whole file (plan→act→observe
|
package/assets/skill/SKILL.md
CHANGED
|
@@ -40,6 +40,8 @@ look at: <files>, and the last failure context to read before acting
|
|
|
40
40
|
allow edits automatically, but ask me before <classes> action policy
|
|
41
41
|
each cycle: plan, then act, then observe the repeated steps (any subset, in order)
|
|
42
42
|
also: <pass>, <pass> extra finishing passes after the goal is met
|
|
43
|
+
use skills: <a>, <b> named skills the loop may invoke during plan/act
|
|
44
|
+
remember in "<file.md>" cross-run memory: read lessons on start, append an outcome on stop
|
|
43
45
|
when it fails: reflect on <focus>, then plan again
|
|
44
46
|
when it passes and the goal is met: stop
|
|
45
47
|
when blocked: ask a human
|
|
@@ -47,6 +49,14 @@ after <N> tries: stop and warn "<message>" thrash guard
|
|
|
47
49
|
a human approves the plan first human plan gate
|
|
48
50
|
a human reviews before stopping human review gate
|
|
49
51
|
a human approves before <action> stage gate (in a stage)
|
|
52
|
+
|
|
53
|
+
# config tier (top of file): how the loop is powered & scheduled
|
|
54
|
+
use the <method> method pull a preset (e.g. BMAD) as the base
|
|
55
|
+
models: fast <m>, strong <m> model tiering — plan/reflect/also→fast, act→strong
|
|
56
|
+
(cascades; override e.g. `act fast`, `all strong`)
|
|
57
|
+
schedule: <when> run unattended on a cadence
|
|
58
|
+
runner: <agent> which agent executes the loop
|
|
59
|
+
target: <dir> operate on another directory/repo
|
|
50
60
|
```
|
|
51
61
|
|
|
52
62
|
Predicates:
|
|
@@ -55,6 +65,8 @@ done when the test "file.spec.ts::name" passes
|
|
|
55
65
|
done when "pnpm test" passes # shell command, exit 0
|
|
56
66
|
done when "semgrep --severity=high" finds nothing # empty output
|
|
57
67
|
done when a human confirms "looks right"
|
|
68
|
+
done when the skill "email-review" approves # a review skill: approved / not
|
|
69
|
+
done when the skill "email-review" scores 8 or more # a review skill: numeric threshold
|
|
58
70
|
```
|
|
59
71
|
|
|
60
72
|
Rules: indentation is structural (two spaces); `loop`/`pipeline` at column 0; comments
|
|
@@ -122,10 +134,23 @@ Walk these quickly, naming the keyword each time so they learn it:
|
|
|
122
134
|
6. **Human gates** → `a human approves the plan first` / `a human reviews before stopping`
|
|
123
135
|
— default none unless the work is risky.
|
|
124
136
|
7. **Git** → state the safe default ("branch, commit when the goal is met, never push to
|
|
125
|
-
`main`"); ask if they want a PR, a worktree, or to work in place.
|
|
137
|
+
`main`"); ask if they want a PR, a worktree, or to work in place. (Full grammar below.)
|
|
138
|
+
8. **Models (LLM policy)** → `models:` — which model does the work. Default: one model
|
|
139
|
+
throughout (the session's). Offer **tiering** for cost/speed: `models: fast <model>,
|
|
140
|
+
strong <model>` → plan/reflect/also run on *fast*, act runs on *strong*; cascades, and
|
|
141
|
+
you can override per phase (`act fast`, `all strong`).
|
|
142
|
+
9. **Schedule / runner / target (config tier — only if automating)** → ask only when the
|
|
143
|
+
loop runs unattended or against another repo: `schedule: <when>` (run on a cadence),
|
|
144
|
+
`runner: <agent>` (which agent executes), `target: <dir>` (operate on another directory).
|
|
145
|
+
Skip silently for a normal in-session loop.
|
|
146
|
+
|
|
147
|
+
Don't forget the menu in Step 2 also covers `use the <method> method` — pull a whole
|
|
148
|
+
preset (e.g. BMAD) instead of hand-picking passes.
|
|
126
149
|
|
|
127
150
|
Offer the defaults inline (*"I'll add a tests + security pass, gate the migration, a
|
|
128
|
-
6-try guard, work on a branch — sound right?"*) so the
|
|
151
|
+
6-try guard, work on a branch, one model throughout, no schedule — sound right?"*) so the
|
|
152
|
+
whole interview is one exchange. Name every topic once even when you default it, so the
|
|
153
|
+
user knows the knob exists and can override it.
|
|
129
154
|
Then **write the `.loop`**, always with a real `done when` and a thrash guard, **print
|
|
130
155
|
its flow** (below), and offer to run it.
|
|
131
156
|
|
|
@@ -162,10 +187,19 @@ the user explicitly asks for the headless runner.)
|
|
|
162
187
|
1. **Read the file.** (Or, if the `loop` CLI is installed: `loop parse <file> --json` to
|
|
163
188
|
get the structured spec.)
|
|
164
189
|
2. **Execute the loop's semantics, narrating each step:**
|
|
190
|
+
- **memory** — if the loop has `remember in "<file>"`, read that file first (skip if it
|
|
191
|
+
doesn't exist yet) and let its lessons inform your first plan. When the loop stops,
|
|
192
|
+
append a dated entry: `## <date> — <outcome>` with the goal, attempts, and the run's
|
|
193
|
+
lesson (your last reflection). This is how the loop improves across runs.
|
|
165
194
|
- **plan** — inspect the `look at:` files; decide the smallest change toward the goal.
|
|
195
|
+
If the loop declares `use skills:`, you may invoke those named skills (via the Skill
|
|
196
|
+
tool) to do the work — coordinate them rather than re-deriving everything inline.
|
|
166
197
|
- **act** — make the edits. Honor the policy: for `ask me before <X>`, ask the user
|
|
167
198
|
before doing X (migrations, pushes, etc.); auto classes you may do directly.
|
|
168
|
-
- **observe** — run the `done when`
|
|
199
|
+
- **observe** — run the `done when` check and read pass/fail. For a command or named test,
|
|
200
|
+
run it. For `the skill "<name>" approves` / `scores N or more`, invoke that review skill
|
|
201
|
+
on the work and read back its verdict (approved/rejected, or a score vs. the threshold) —
|
|
202
|
+
this is how an abstract goal gets a verifiable check.
|
|
169
203
|
- on **fail** → **reflect** on why (use the failure output), then **plan again** (the
|
|
170
204
|
back-edge). Repeat.
|
|
171
205
|
- **stop** when `done when` passes, or after the thrash guard's N tries (state the
|
|
@@ -270,8 +304,41 @@ and honor the policy: if `push when done` is set and the current branch is `main
|
|
|
270
304
|
|
|
271
305
|
---
|
|
272
306
|
|
|
307
|
+
## Global library — save a loop, reuse it in any project
|
|
308
|
+
|
|
309
|
+
The user keeps a personal library of loops at **`~/.claude/loopflow/`** — one
|
|
310
|
+
`<name>.loop` per saved loop. It lives beside the installed skill, so a loop saved once is
|
|
311
|
+
runnable from **every** repo. The library is driven entirely from this chat; there is no
|
|
312
|
+
terminal command for it. Create the directory on first save (`mkdir -p ~/.claude/loopflow`).
|
|
313
|
+
|
|
314
|
+
Four operations — recognize them from `/loopflow <verb>` or from plain language:
|
|
315
|
+
|
|
316
|
+
- **save** — *"save this as `<name>`"*, *"save it to my library"*, `/loopflow save …`
|
|
317
|
+
Write the loop's `.loop` source to `~/.claude/loopflow/<name>.loop`. Take `<name>` from
|
|
318
|
+
the user; if they don't give one, slugify the loop's name (`"fix the auth test"` →
|
|
319
|
+
`fix-the-auth-test`). **If that file already exists, show the saved version and confirm
|
|
320
|
+
before overwriting.** Report the path you wrote.
|
|
321
|
+
|
|
322
|
+
- **list** — `/loopflow list`, *"what loops do I have saved"*
|
|
323
|
+
List every `*.loop` in `~/.claude/loopflow/`. For each, print `name — <goal>` (add the
|
|
324
|
+
one-line shape when it helps). An empty or missing dir → say it's empty and how to save one.
|
|
325
|
+
|
|
326
|
+
- **run** — `/loopflow run <name>`, *"run my security loop here"*
|
|
327
|
+
Read `~/.claude/loopflow/<name>.loop` and run it **in the current repo**, exactly as in
|
|
328
|
+
*Running a .loop (in this session)* above. A bare `<name>` means the library; a path or a
|
|
329
|
+
name ending in `.loop` is a local file, so the library never shadows a loop in the repo.
|
|
330
|
+
If `<name>` isn't in the library, say so and offer `list`.
|
|
331
|
+
|
|
332
|
+
- **remove** — `/loopflow remove <name>`, *"delete my `<name>` loop"*
|
|
333
|
+
Delete `~/.claude/loopflow/<name>.loop` after confirming. If it doesn't exist, say so.
|
|
334
|
+
|
|
335
|
+
These are plain files — the user may also open or edit them directly. Saving is a copy, so
|
|
336
|
+
removing a library entry never touches the original loop in a repo.
|
|
337
|
+
|
|
338
|
+
---
|
|
339
|
+
|
|
273
340
|
## Reference
|
|
274
341
|
|
|
275
342
|
The full language reference is in `AGENTS.md` and `docs/MANUAL.md` of the loop-lang repo;
|
|
276
|
-
the CLI (`loop run|viz|
|
|
343
|
+
the CLI (`loop-run run|viz|parse`) and the VSCode extension are alternative ways to run
|
|
277
344
|
the same `.loop` files.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@loop-lang/loop",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Install
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Install LoopFlow (.loop) into any repo so Claude Code — or any agent — can author and run self-correcting, human-gated coding loops.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"publishConfig": { "access": "public" },
|
|
7
7
|
"type": "module",
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
"scripts": {
|
|
14
14
|
"sync-assets": "node scripts/sync-assets.mjs",
|
|
15
15
|
"prepack": "node scripts/sync-assets.mjs",
|
|
16
|
+
"postinstall": "node src/postinstall.mjs",
|
|
16
17
|
"test": "node scripts/sync-assets.mjs && node --test test/*.test.mjs"
|
|
17
18
|
}
|
|
18
19
|
}
|
package/src/cli.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// @loop-lang/loop — the installer CLI. `loop init` drops Loop into a repo so any
|
|
3
3
|
// agent can author + run .loop files. Running loops happens in your agent (the
|
|
4
|
-
// /loopflow skill) or headless via the full @loop/runtime CLI.
|
|
4
|
+
// /loopflow skill) or headless via the full @loop-lang/runtime CLI.
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
import { dirname, join, resolve } from "node:path";
|
|
7
7
|
import { init } from "./init.mjs";
|
|
@@ -17,7 +17,7 @@ usage:
|
|
|
17
17
|
|
|
18
18
|
init options:
|
|
19
19
|
--dir <path> install into <path> (default: current directory)
|
|
20
|
-
--global install the /loopflow skill into ~/.claude/skills (
|
|
20
|
+
--global install the /loopflow skill into ~/.claude/skills (done automatically on \`npm install -g\`)
|
|
21
21
|
--no-skill don't install the Claude Code /loopflow skill
|
|
22
22
|
--no-example don't write examples/fix_test.loop
|
|
23
23
|
--no-claude-md don't write the CLAUDE.md pointer (written by default)
|
|
@@ -29,7 +29,7 @@ init options:
|
|
|
29
29
|
after init:
|
|
30
30
|
• Claude Code: open a chat in the repo and say /loopflow run examples/fix_test.loop
|
|
31
31
|
• any agent: it reads AGENTS.md and can author + run .loop files
|
|
32
|
-
• headless: install @loop/runtime for loop run <file>`;
|
|
32
|
+
• headless: install @loop-lang/runtime for loop-run run <file>`;
|
|
33
33
|
|
|
34
34
|
function flag(argv, name) { return argv.includes(name); }
|
|
35
35
|
function opt(argv, name) { const i = argv.indexOf(name); return i >= 0 ? argv[i + 1] : undefined; }
|
|
@@ -70,8 +70,8 @@ async function main(argv) {
|
|
|
70
70
|
return;
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
if (["run", "parse", "
|
|
74
|
-
console.error(`\`loop ${cmd}\` runs in your agent (the /loopflow skill) or via the full runtime CLI (@loop/runtime).\nThis package installs Loop — try \`loop init\`. See \`loop help\`.`);
|
|
73
|
+
if (["run", "parse", "viz", "show", "ls"].includes(cmd)) {
|
|
74
|
+
console.error(`\`loop ${cmd}\` runs in your agent (the /loopflow skill) or via the full runtime CLI: \`loop-run ${cmd}\` (install @loop-lang/runtime).\nThis package installs Loop — try \`loop init\`. See \`loop help\`.`);
|
|
75
75
|
process.exit(2);
|
|
76
76
|
}
|
|
77
77
|
|
package/src/init.mjs
CHANGED
|
@@ -17,6 +17,7 @@ export function pointer({ skill }) {
|
|
|
17
17
|
"## Loop (`.loop`)",
|
|
18
18
|
"",
|
|
19
19
|
"This repo uses **Loop** — a small natural-language DSL for self-correcting, human-gated coding workflows.",
|
|
20
|
+
"**First time you touch Loop in this repo, read [`AGENTS.md`](./AGENTS.md) end to end before authoring or running anything** — it's the full, current grammar that ships with the repo. Don't rely on prior memory of Loop; it may be stale. Read it once per session so your context is up to date.",
|
|
20
21
|
"Whenever the user wants to build, fix, automate, or ship something as a repeatable/self-correcting workflow — a bug fix, a feature, an epic, even a whole app — **default to authoring a `.loop` file** rather than doing the work ad hoc. Use the grammar in [`AGENTS.md`](./AGENTS.md), interview the user for the goal/verification/gates first, then " + run + ".",
|
|
21
22
|
"Every time you create or change a `.loop`, print its flow so the user can see the shape.",
|
|
22
23
|
].join("\n");
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// Runs after `npm install -g @loop-lang/loop`.
|
|
2
|
+
// On a global install, copies the /loopflow skill to ~/.claude/skills/loopflow
|
|
3
|
+
// so every Claude Code session in every project has access to /loopflow.
|
|
4
|
+
// Skips silently on local installs and when the skill already exists.
|
|
5
|
+
import { cp, mkdir, access } from "node:fs/promises";
|
|
6
|
+
import { homedir } from "node:os";
|
|
7
|
+
import { join, dirname } from "node:path";
|
|
8
|
+
import { fileURLToPath } from "node:url";
|
|
9
|
+
|
|
10
|
+
const isGlobal = process.env.npm_config_global === "true";
|
|
11
|
+
if (!isGlobal) process.exit(0);
|
|
12
|
+
|
|
13
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
14
|
+
const src = join(here, "..", "assets", "skill");
|
|
15
|
+
const dst = join(homedir(), ".claude", "skills", "loopflow");
|
|
16
|
+
|
|
17
|
+
const exists = (p) => access(p).then(() => true, () => false);
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
if (await exists(dst)) {
|
|
21
|
+
console.log(` loop: /loopflow skill already at ~/.claude/skills/loopflow — skipped.`);
|
|
22
|
+
console.log(` Run \`loop init --global --force\` to overwrite.`);
|
|
23
|
+
} else {
|
|
24
|
+
await mkdir(join(homedir(), ".claude", "skills"), { recursive: true });
|
|
25
|
+
await cp(src, dst, { recursive: true });
|
|
26
|
+
console.log(` loop: installed /loopflow skill → ~/.claude/skills/loopflow`);
|
|
27
|
+
console.log(` Open any Claude Code session and type /loopflow to start.`);
|
|
28
|
+
}
|
|
29
|
+
} catch (err) {
|
|
30
|
+
// Non-fatal — don't break the install.
|
|
31
|
+
console.warn(` loop: could not install /loopflow skill: ${err.message}`);
|
|
32
|
+
console.warn(` Run \`loop init --global\` manually to install it.`);
|
|
33
|
+
}
|