@loop-lang/loop 0.1.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/README.md ADDED
@@ -0,0 +1,34 @@
1
+ # @loop-lang/loop
2
+
3
+ Install **Loop** — a small natural-language DSL for self-correcting, human-gated coding loops — into any repo, so **Claude Code or any agent** can author and run `.loop` files.
4
+
5
+ ```sh
6
+ npx @loop-lang/loop init
7
+ ```
8
+
9
+ That scaffolds, into the current repo:
10
+
11
+ - **`AGENTS.md`** — the full Loop language reference. Any agent that opens the repo (Claude Code, Cursor, Copilot, Codex…) now knows how to write a `.loop`.
12
+ - **`.claude/skills/loop`** — the Claude Code `/loop` skill (author + run loops natively in a chat).
13
+ - **`examples/fix_test.loop`** — a starter loop to run.
14
+
15
+ ### Options
16
+
17
+ ```
18
+ loop init [--dir <path>] [--global] [--no-skill] [--no-example]
19
+ [--claude-md] [--cursor] [--copilot] [--all-agents] [--force]
20
+ ```
21
+
22
+ - `--global` — install the skill into `~/.claude/skills` instead of the repo.
23
+ - `--all-agents` — also drop memory pointers for Cursor + Copilot (and `CLAUDE.md`).
24
+ - `--force` — overwrite an existing skill / example.
25
+
26
+ Re-running `init` is safe: the `AGENTS.md` block is managed between markers and updated in place, not duplicated.
27
+
28
+ ### After install
29
+
30
+ - **Claude Code:** open a chat in the repo → `/loop run examples/fix_test.loop`, or just describe the work and the agent writes the `.loop`.
31
+ - **Any agent:** it reads `AGENTS.md` and can author + run loops the same way.
32
+ - **Headless:** install the full runtime for `loop run <file>`.
33
+
34
+ Learn the language: the [tutorial](https://github.com/tickets-forge-dev/loop-lang), the keyword reference, and the playable Loop Lab.
@@ -0,0 +1,255 @@
1
+ # AGENTS.md — authoring Loop (`.loop`) flows
2
+
3
+ This file teaches an AI assistant (Claude Code, Copilot, Cursor, etc.) how to write
4
+ **Loop** flows. When a user asks you to design a staged, self-correcting, or human-gated
5
+ coding workflow — "set up a loop to fix X", "turn this epic into a pipeline", "automate
6
+ this multi-step task" — author a `.loop` file using the grammar below, then let the user
7
+ run it with `loop run file.loop`.
8
+
9
+ Loop is a small natural-language DSL. A `.loop` file describes the *movement* of an AI
10
+ coding loop: its objective, the context it may read, the actions it's allowed, how it
11
+ verifies itself, when it stops, and where a human steps in. The five knobs —
12
+ **objective, context, actions, verification, stopping rules** — are first-class instead
13
+ of buried in a prompt.
14
+
15
+ ## When to write a `.loop`
16
+
17
+ Write one when the work is a *repeatable, verifiable* loop or a sequence of them:
18
+ bug fixes with a test, refactors gated by a check, an epic broken into stories, a
19
+ migration with a verification step. Don't write one for a one-off question or a trivial
20
+ edit — just do those directly.
21
+
22
+ **Interview the user before writing it.** Walk the five decisions, asking the
23
+ high-leverage questions and offering defaults for the rest: (1) the **goal**;
24
+ (2) the **`done when`** check (test / command / scan finds-nothing / human);
25
+ (3) **`look at`** context; (4) the **action policy** (what's risky enough to gate);
26
+ (5) **stopping** (reflect on failure + an `after N tries` guard). Then the
27
+ **human gates** and the **git strategy** (default: branch + commit when done,
28
+ never push to `main`; ask if they want a PR or a worktree). Offer the defaults
29
+ inline so a confident user can accept everything at once.
30
+
31
+ ## Vocabulary (the whole language)
32
+
33
+ ```
34
+ loop "<name>": a self-correcting loop
35
+ pipeline "<name>": a sequence of stages (an epic)
36
+ stage "<name>": one stage of a pipeline (its body is a loop; a story)
37
+ flow "<name>": a chain of loop files (each step runs a whole .loop file)
38
+ run "<file>": first step — runs the file; its text result is passed forward
39
+ then run "<file>": subsequent step — receives the previous result as context
40
+ a human approves first (optional per-step human gate before the step runs)
41
+ with the result of <name> (reference a named step's output instead of auto-carry)
42
+ for each <var> in "<file>": iterate items from a .yaml or .md file; run the template once per item
43
+ run "<template>": template receives the item text as context; fail → ask continue/stop
44
+
45
+ goal: <text> what "done" means, in plain language
46
+ done when <predicate> how the loop verifies itself (see Predicates)
47
+ look at: <files>, and the last failure context the agent reads before acting (items are file paths or plain-language descriptions the agent resolves to files)
48
+ allow edits automatically, but ask me before <classes> action policy
49
+ each cycle: plan, then act, then observe the repeated steps (any subset, in order)
50
+ also: <pass>, <pass> extra finishing passes run after the goal is met
51
+ reflect turn a failure into context for the next plan (the back-edge)
52
+
53
+ when it passes and the goal is met: stop
54
+ when it fails: reflect on <focus>, then plan again
55
+ when blocked: ask a human
56
+ after <N> tries: stop and warn "<message>"
57
+
58
+ a human approves the plan first (human authors/approves the plan before acting)
59
+ a human reviews before stopping (human judges the result before the loop stops)
60
+ a human approves before <action> (a blocking gate before a stage, e.g. deploy)
61
+
62
+ plan from the archon project "<name>" (source the plan from Archon instead of generating)
63
+
64
+ use the <method> method schedule: <when> runner: <agent> target: <dir> (config tier)
65
+ models: fast <model>, strong <model> model tiering: plan/reflect/also→fast, act→strong (cascades; override e.g. `act fast`, `all strong`)
66
+ ```
67
+
68
+ ### Predicates (`done when …`)
69
+
70
+ ```
71
+ done when the test "billing.spec.ts::apostrophe" passes # a named test
72
+ done when "pnpm test" passes # a shell command, exit 0
73
+ done when "semgrep --severity=high" finds nothing # a shell command, empty output
74
+ done when a human confirms "looks right at 375px" # a human check
75
+ ```
76
+
77
+ The command in a predicate runs in the user's shell with their privileges (like an npm
78
+ script). It IS meant to be a real command. Prefer a fast, deterministic check.
79
+
80
+ ### `flow` — chaining loops across files
81
+
82
+ A `flow` sequences multiple `.loop` files. Each step runs the whole file (plan→act→observe
83
+ cycle) and passes its text result forward as context for the next step. The chain is
84
+ fail-fast: a step that ends unsatisfied stops the rest.
85
+
86
+ ```loop
87
+ flow "ship":
88
+ run "build.loop"
89
+ then run "test.loop"
90
+ then run "deploy.loop":
91
+ a human approves first
92
+ ```
93
+
94
+ - `run "<file>"` — first step; the file path is relative to the flow file.
95
+ - `then run "<file>"` — subsequent steps; automatically receive the previous step's text summary.
96
+ - `a human approves first` — optional per-step gate; blocks until approved.
97
+ - `with the result of <name>` — reference a named step's output explicitly instead of auto-carry.
98
+
99
+ ### `for each` — iterate a plan, run a template per item
100
+
101
+ Inside a `flow`, `for each` reads a list from a YAML or Markdown file and runs a template
102
+ once per entry. The entry's text becomes the template's context (what to build).
103
+
104
+ ```loop
105
+ flow "deliver":
106
+ for each item in "plan.yaml":
107
+ run "item-template.loop"
108
+ ```
109
+
110
+ - `for each <var> in "<file>":` — source must be a `.yaml` file (a list or a single-key
111
+ list like `items:`) or a `.md` file (splits on `## ` sections).
112
+ - `run "<template>"` — the template runs once per item; the item text arrives as context.
113
+ - A failed item pauses the flow and asks whether to continue with the next item or stop.
114
+ - Method-neutral: works with any checklist, not only BMAD. See `examples/foreach/` for a
115
+ generic bundle and `examples/bmad/atoz/` for BMAD as one example method.
116
+
117
+ ## Rules
118
+
119
+ - **Indentation matters.** `loop` / `pipeline` / `flow` at column 0; their body indented
120
+ two spaces; a `stage`'s body indented under the stage.
121
+ - A `loop` needs a `goal`. A `pipeline` needs at least one `stage`.
122
+ - **An epic → a `pipeline`; each story → a `stage`.** Stages run in order; a failing
123
+ stage halts the rest.
124
+ - **Scope each loop with `look at:`** so the agent follows the existing architecture and
125
+ makes the smallest change, instead of writing greenfield code. Items can be exact file
126
+ paths or plain-language descriptions (e.g. `the billing form`) — the agent resolves
127
+ descriptions to the actual files before planning.
128
+ - **Put human gates on risky work** — payments, migrations, deploys, anything
129
+ irreversible. Use `ask me before …` for action policy, `a human approves before …`
130
+ for a hard stage gate.
131
+ - Output only valid `.loop` syntax. Comments start with `#`.
132
+
133
+ ## Example — a single loop
134
+
135
+ ```loop
136
+ loop "fix billing apostrophe bug":
137
+ goal: settings save when the company name has an apostrophe
138
+ done when the test "billing.spec.ts::apostrophe" passes
139
+
140
+ look at: billing/form.tsx, api/settings.ts, schema/settings.ts, and the last failure
141
+ allow edits automatically, but ask me before migrations or pushes
142
+
143
+ each cycle: plan, then act, then observe
144
+ when it passes and the goal is met: stop
145
+ when it fails: reflect on which layer broke, then plan again
146
+ when blocked: ask a human
147
+ also: polish the code, run a security check
148
+ after 6 tries: stop and warn "thrashing"
149
+ ```
150
+
151
+ ## Example — an epic with stories
152
+
153
+ ```loop
154
+ pipeline "epic: checkout v2":
155
+
156
+ stage "story: cart totals":
157
+ goal: cart shows correct totals with tax
158
+ look at: src/cart/, src/tax/
159
+ done when "pnpm test cart" passes
160
+ each cycle: plan, then act, then observe
161
+ when it fails: reflect, then plan again
162
+
163
+ stage "story: checkout submit":
164
+ goal: order submits and payment is captured
165
+ a human approves before charging the card
166
+ done when "pnpm test checkout" passes
167
+ each cycle: act, then observe
168
+ ```
169
+
170
+ ## Git strategy
171
+
172
+ A `git:` block sets the version-control strategy for the whole file (config tier, before
173
+ any definition) or for a single loop (inside the loop body).
174
+
175
+ **Built-in default (no `git:` block):** work on a branch, commit when the goal is met,
176
+ no push. This applies whenever no git block is present at any level.
177
+
178
+ ### Line forms
179
+
180
+ ```
181
+ work in place # edit the current branch as-is
182
+ work on a branch # create / switch to a feature branch (default)
183
+ work on a branch "my-feature" # explicit branch name
184
+ work in a worktree # isolated git worktree
185
+ work in a worktree "my-worktree" # named worktree
186
+
187
+ commit when the goal is met # one commit on success (default)
188
+ commit each cycle # commit after every cycle
189
+ commit each story # commit after each stage
190
+ commit never / do not commit # no automatic commits
191
+
192
+ push when done # push the branch on completion
193
+ do not push # no push (default)
194
+
195
+ open a pull request # open a PR after pushing
196
+ ```
197
+
198
+ ### Cascade (lowest wins)
199
+
200
+ 1. Built-in default — branch + commit-when-done, no push.
201
+ 2. File-level `git:` block — applies to all loops in the file.
202
+ 3. Per-loop `git:` block — refines commit cadence for that loop only.
203
+
204
+ A `use the <method>` preset may carry a `git:` block at file level; the file's own block
205
+ overrides it.
206
+
207
+ ### Always-on safety
208
+
209
+ - **Never push to `main` or `master`.** This is unconditional — no `git:` block can
210
+ override it. A `push when done` directive with the current branch being protected is an
211
+ error that surfaces before the loop runs.
212
+ - **`work in place` + `push when done` on a protected branch** is also an up-front error.
213
+
214
+ ### Example
215
+
216
+ ```loop
217
+ git:
218
+ work on a branch
219
+ commit when the goal is met
220
+ push when done
221
+ open a pull request
222
+
223
+ loop "add a healthcheck endpoint":
224
+ goal: GET /healthz returns 200 with a JSON status
225
+ done when "pnpm test health" passes
226
+ look at: the http server and the routes module, and the last failure
227
+ each cycle: plan, then act, then observe
228
+ when it fails: reflect, then plan again
229
+ after 6 tries: stop and warn "healthcheck stuck"
230
+ ```
231
+
232
+ ## Show the flow — every time it changes
233
+
234
+ Whenever you create or edit a `.loop`, print its flow so the user sees the shape.
235
+ Run `loop show file.loop`, or render the compact ASCII yourself: the cycle
236
+ (`plan → act → observe`), the `↺` reflect back-edge, the `✓ done when` check, the
237
+ `⛔` thrash guard, and any `👤` gates. For a pipeline, list stages in order; for a
238
+ flow, show the file chain. `loop ls` lists every loop in the repo.
239
+
240
+ ## Running what you wrote
241
+
242
+ - `loop run file.loop` — execute it on Claude Code (plan/act/observe, reflect on failure,
243
+ verify with `done when`, pause at human gates).
244
+ - `loop show file.loop` — print the loop's flow as compact ASCII (and `loop ls` to list them).
245
+ - `loop viz file.loop` — open a visual HTML schematic of the flow.
246
+ - `loop export file.loop` — emit an Archon workflow YAML (optional interop).
247
+
248
+ ## Authoring checklist
249
+
250
+ 1. One coherent objective per `loop`; one story per `stage`.
251
+ 2. A real, fast `done when` predicate — never claim done without a check.
252
+ 3. `look at:` the relevant files so the agent stays inside the architecture.
253
+ 4. A `when it fails: reflect, then plan again` so the loop self-corrects.
254
+ 5. An `after N tries` thrash guard so it can't spin forever.
255
+ 6. Human gates on anything irreversible.
@@ -0,0 +1,6 @@
1
+ loop "fix test":
2
+ goal: the checkout tax test passes
3
+ done when the test "checkout.spec.ts::tax" passes
4
+
5
+ each cycle: plan, then act, then observe
6
+ when it fails: reflect, then plan again
@@ -0,0 +1,237 @@
1
+ ---
2
+ name: loop
3
+ description: Create and run Loop (.loop) flows — a natural-language DSL for loop engineering. Use when the user wants to author, write, run, or execute a self-correcting or human-gated AI coding loop, turn an epic into a pipeline, fix a bug "as a loop", or mentions a .loop file or "loop engineering".
4
+ ---
5
+
6
+ # Loop
7
+
8
+ Loop is a small natural-language DSL for **loop engineering**: a `.loop` file describes a
9
+ staged, self-correcting, human-gated coding workflow — its objective, the context it may
10
+ read, the actions it may take, how it verifies itself, when it stops, and where a human
11
+ steps in.
12
+
13
+ You do two things with this skill: **create** `.loop` files, and **run** them — natively,
14
+ in this conversation, so the user watches every step and answers gates right here.
15
+
16
+ ---
17
+
18
+ ## The language
19
+
20
+ Vocabulary (the whole DSL):
21
+
22
+ ```
23
+ loop "<name>": a self-correcting loop
24
+ pipeline "<name>": a sequence of stages (an epic)
25
+ stage "<name>": one stage of a pipeline (its body is a loop; a story)
26
+
27
+ flow "<name>": a chain of whole .loop files, run in order (handoff is text)
28
+ run "<file.loop>" a flow step: run that whole file
29
+ then run "<file.loop>" the next step; the prior file's summary carries forward as context
30
+ ... with the result of <step> pull the handoff from a named earlier step instead of the previous
31
+ for each <var> in "<file>": run the child template once per item in <file>
32
+ run "<template.loop>"
33
+
34
+ # `for each` source: .yaml/.yml (a list, or items under a single key) or .md (each `## ` section).
35
+ # Each item's text becomes the template's context for that run.
36
+
37
+ goal: <text> what "done" means, in plain language
38
+ done when <predicate> how the loop verifies itself
39
+ look at: <files>, and the last failure context to read before acting
40
+ allow edits automatically, but ask me before <classes> action policy
41
+ each cycle: plan, then act, then observe the repeated steps (any subset, in order)
42
+ also: <pass>, <pass> extra finishing passes after the goal is met
43
+ when it fails: reflect on <focus>, then plan again
44
+ when it passes and the goal is met: stop
45
+ when blocked: ask a human
46
+ after <N> tries: stop and warn "<message>" thrash guard
47
+ a human approves the plan first human plan gate
48
+ a human reviews before stopping human review gate
49
+ a human approves before <action> stage gate (in a stage)
50
+ ```
51
+
52
+ Predicates:
53
+ ```
54
+ done when the test "file.spec.ts::name" passes
55
+ done when "pnpm test" passes # shell command, exit 0
56
+ done when "semgrep --severity=high" finds nothing # empty output
57
+ done when a human confirms "looks right"
58
+ ```
59
+
60
+ Rules: indentation is structural (two spaces); `loop`/`pipeline` at column 0; comments
61
+ start with `#`. An epic → a `pipeline`; each story → a `stage`.
62
+
63
+ ---
64
+
65
+ ## Creating a .loop — interview the user first
66
+
67
+ Don't silently guess the loop. **Walk the five decisions with the user**, asking
68
+ the high-leverage questions out loud and offering a default for the rest, so a
69
+ confident user can accept everything in one reply. Ask one topic at a time:
70
+
71
+ 1. **Goal (objective)** — "What's the goal — what does *done* look like?"
72
+ Required; never guess this one.
73
+ 2. **Verification — `done when`** — "How do we know it's done: a test passing, a
74
+ shell command passing, a scan that must *find nothing*, or a human confirming?"
75
+ The most important answer — always ask.
76
+ 3. **Context — `look at`** — "What should it read first?" Offer to infer the files
77
+ from the repo; append `and the last failure`.
78
+ 4. **Actions — policy** — "Anything risky to gate — migrations, pushes, deploys?"
79
+ Default offered: edits automatically, nothing else gated.
80
+ 5. **Stopping — transitions + guard** — confirm the default (reflect on failure,
81
+ `after N tries: stop and warn`); ask for N only if they care.
82
+
83
+ Then two more that shape the run:
84
+
85
+ 6. **Human gates** — "Approve the plan before any work? Review before it stops?"
86
+ Default: none unless the work is risky.
87
+ 7. **Git strategy** — state the safe default ("work on a branch, commit when the
88
+ goal is met, never push to `main`") and ask if they want a PR, a worktree, or
89
+ to work in place.
90
+
91
+ Offer the defaults inline (e.g. *"I'll gate nothing, add a 6-try guard, and work
92
+ on a branch — ok?"*) so the whole interview can be one exchange. Then **write the
93
+ `.loop`**, scoping it with `look at:` and always giving it a real `done when` and a
94
+ thrash guard. Finally **print its flow** (below) and offer to run it.
95
+
96
+ ## Show the flow — every time it changes
97
+
98
+ Whenever you **create or edit** a `.loop`, immediately print its flow so the user
99
+ watches the shape evolve. If the `loop` CLI is installed, run `loop show <file>`.
100
+ Otherwise render the same compact ASCII yourself:
101
+
102
+ ```
103
+ loop "fix test"
104
+ ↻ plan → act → observe (each cycle)
105
+ ↺ on fail: reflect → plan (the back-edge)
106
+ ✓ done when: test "checkout.spec.ts::tax"
107
+ ⛔ guard: after 6 tries → stop & warn "stuck"
108
+ · goal: the tax line is correct
109
+ ```
110
+
111
+ For a **pipeline**, list the stages in order and mark 👤 gates; for a **flow**,
112
+ show the file chain (`a.loop → b.loop → …`). `loop ls` lists every loop in the repo.
113
+
114
+ ---
115
+
116
+ ## Running a .loop (in this session)
117
+
118
+ Prefer running it **yourself, here** — that way the whole loop is visible in the
119
+ conversation and the user answers gates inline. (Only shell out to the `loop run` CLI if
120
+ the user explicitly asks for the headless runner.)
121
+
122
+ 1. **Read the file.** (Or, if the `loop` CLI is installed: `loop parse <file> --json` to
123
+ get the structured spec.)
124
+ 2. **Execute the loop's semantics, narrating each step:**
125
+ - **plan** — inspect the `look at:` files; decide the smallest change toward the goal.
126
+ - **act** — make the edits. Honor the policy: for `ask me before <X>`, ask the user
127
+ before doing X (migrations, pushes, etc.); auto classes you may do directly.
128
+ - **observe** — run the `done when` command (or named test) and read pass/fail.
129
+ - on **fail** → **reflect** on why (use the failure output), then **plan again** (the
130
+ back-edge). Repeat.
131
+ - **stop** when `done when` passes, or after the thrash guard's N tries (state the
132
+ warning), or if genuinely blocked (ask the user).
133
+ - **human gates:** `a human approves the plan first` → present the plan and wait for
134
+ approval before acting. `a human reviews before stopping` → ask before declaring done.
135
+ `a human approves before <X>` → ask before that stage runs.
136
+ - **pipelines:** run stages in order; if a stage can't be satisfied, halt the rest.
137
+ - **flows:** run each referenced file in order, the *whole* file. After each, carry a
138
+ short text summary of how it went forward as context for the next file. If a file
139
+ isn't satisfied, halt the rest (fail-fast). `with the result of <step>` redirects
140
+ which earlier summary to carry.
141
+ - **for each `<var>` in `<file>`:** read the source file and split it into items
142
+ (`.yaml` list entries, or `.md` `## ` sections). Run the template loop once per item,
143
+ giving the template that item's text as its context. If an item's checklist fails,
144
+ pause and ask the user: continue to the next item, or stop the whole flow? Continuing
145
+ accepts that item and proceeds; reaching the end means done.
146
+ - **`also:`** finishing passes run only after the goal is met (skip them if it failed).
147
+ 3. **Report a concise trace** — one line per cycle step (plan / act / observe = PASS|fail /
148
+ reflect / stop), and the final outcome.
149
+
150
+ Because you are the one running it, the user sees the real work — file reads, edits,
151
+ command output — as part of this session, and answers any gate right in the chat.
152
+
153
+ ---
154
+
155
+ ## Interactive discovery (the front of an A-to-Z flow)
156
+
157
+ A discovery/planning step is just a loop whose goal is to produce a planning artifact (a
158
+ spec, PRD, or plan file). Run it as a real conversation:
159
+
160
+ - Interview the user — ask the questions the method calls for — across as many turns as it
161
+ takes. You're naturally suspended between their answers, so a long session (even an hour)
162
+ is fine; there's nothing to "wait" on.
163
+ - The step is **done when its `done when` artifact check passes** — e.g. the plan file
164
+ exists and has the required sections — NOT when the conversation goes quiet. Re-check the
165
+ artifact; when it validates, move on. (The questions come from the loop's goal/context —
166
+ i.e. the method — not from this skill.)
167
+
168
+ So a full method, end to end, is a `flow`:
169
+
170
+ flow "deliver: <feature>":
171
+ run "discover.loop" # conversation: interview → write the plan file
172
+ then run "design.loop" # design from it; a human approves
173
+ then for each item in "plan.yaml":
174
+ run "item-template.loop" # the per-item checklist, once per item
175
+
176
+ `discover.loop` ends via e.g. `done when "<validator> plan.yaml"`; each item then runs the
177
+ same checklist. (Name things to taste — a BMAD setup might use `story`/`sprint.yaml`.)
178
+
179
+ ---
180
+
181
+ ## Git strategy
182
+
183
+ A `git:` block sets the version-control strategy for the whole file (config tier) or for
184
+ a single loop. When there is no `git:` block at all the built-in default applies:
185
+ **work on a branch, commit when the goal is met, no push**.
186
+
187
+ ### Line forms
188
+
189
+ ```
190
+ work in place # edit the current branch as-is
191
+ work on a branch # create / switch to a feature branch (default)
192
+ work on a branch "my-feature" # name the branch explicitly
193
+ work in a worktree # isolated git worktree
194
+ work in a worktree "my-worktree" # named worktree
195
+
196
+ commit when the goal is met # one commit when done (default)
197
+ commit each cycle # commit after every plan→act→observe cycle
198
+ commit each story # commit after each stage in a pipeline
199
+ commit never / do not commit # no automatic commits
200
+
201
+ push when done # push the branch when the loop finishes
202
+ do not push # no push (default)
203
+
204
+ open a pull request # open a PR after pushing (requires push when done)
205
+ ```
206
+
207
+ ### Cascade
208
+
209
+ Settings resolve in three layers, each refining the one above:
210
+
211
+ 1. **Built-in default** — branch + commit-when-done, no push.
212
+ 2. **File-level `git:` block** — placed at the top of the `.loop` file, before any loop definition; applies to every loop in the file.
213
+ 3. **Per-loop `git:` block** — placed inside a single `loop` body; refines the commit cadence for that loop only.
214
+
215
+ A `use the <method>` preset may also carry a `git:` block; it applies at the file level and is then overridden by the file's own `git:` block if present.
216
+
217
+ ### Always-on safety
218
+
219
+ Two protections are unconditional and cannot be overridden by any `git:` block:
220
+
221
+ - **Never push to `main` or `master`.** If the current branch is `main` or `master` (or a branch whose name matches the protected set), any `push when done` directive is an error that surfaces *before the loop runs*, not after.
222
+ - **`work in place` + `push when done` on a protected branch** is also rejected up front.
223
+
224
+ ### In-chat runner note
225
+
226
+ When you run a loop *inside this conversation* (the `/loop` skill), you are the git
227
+ operator — you execute plan/act/observe yourself. Before acting, check the `git:` block
228
+ and honor the policy: if `push when done` is set and the current branch is `main` or
229
+ `master`, refuse with a clear message rather than pushing.
230
+
231
+ ---
232
+
233
+ ## Reference
234
+
235
+ The full language reference is in `AGENTS.md` and `docs/MANUAL.md` of the loop-lang repo;
236
+ the CLI (`loop run|viz|export|parse`) and the VSCode extension are alternative ways to run
237
+ the same `.loop` files.
package/package.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "@loop-lang/loop",
3
+ "version": "0.1.0",
4
+ "description": "Install Loop (.loop) into any repo so Claude Code — or any agent — can author and run self-correcting, human-gated coding loops.",
5
+ "license": "Apache-2.0",
6
+ "publishConfig": { "access": "public" },
7
+ "type": "module",
8
+ "bin": { "loop": "src/cli.mjs" },
9
+ "files": ["src", "assets", "README.md"],
10
+ "engines": { "node": ">=18" },
11
+ "keywords": ["loop", "agent", "claude", "ai", "workflow", "dsl", "loop-engineering"],
12
+ "repository": { "type": "git", "url": "https://github.com/tickets-forge-dev/loop-lang.git", "directory": "packages/cli" },
13
+ "scripts": {
14
+ "sync-assets": "node scripts/sync-assets.mjs",
15
+ "prepack": "node scripts/sync-assets.mjs",
16
+ "test": "node scripts/sync-assets.mjs && node --test test/*.test.mjs"
17
+ }
18
+ }
package/src/cli.mjs ADDED
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env node
2
+ // @loop-lang/loop — the installer CLI. `loop init` drops Loop into a repo so any
3
+ // agent can author + run .loop files. Running loops happens in your agent (the
4
+ // /loop skill) or headless via the full @loop/runtime CLI.
5
+ import { fileURLToPath } from "node:url";
6
+ import { dirname, join, resolve } from "node:path";
7
+ import { init } from "./init.mjs";
8
+
9
+ const here = dirname(fileURLToPath(import.meta.url));
10
+ const ASSETS = join(here, "..", "assets");
11
+
12
+ const HELP = `loop — install Loop into your repo so any agent can author + run .loop files
13
+
14
+ usage:
15
+ loop init [options] scaffold Loop into the current repo
16
+ loop help show this
17
+
18
+ init options:
19
+ --dir <path> install into <path> (default: current directory)
20
+ --global install the /loop skill into ~/.claude/skills (not the repo)
21
+ --no-skill don't install the Claude Code /loop skill
22
+ --no-example don't write examples/fix_test.loop
23
+ --claude-md also write a CLAUDE.md pointer
24
+ --cursor also write .cursor/rules/loop.md
25
+ --copilot also write .github/copilot-instructions.md
26
+ --all-agents CLAUDE.md + Cursor + Copilot pointers
27
+ --force overwrite the skill / example if they already exist
28
+
29
+ after init:
30
+ • Claude Code: open a chat in the repo and say /loop run examples/fix_test.loop
31
+ • any agent: it reads AGENTS.md and can author + run .loop files
32
+ • headless: install @loop/runtime for loop run <file>`;
33
+
34
+ function flag(argv, name) { return argv.includes(name); }
35
+ function opt(argv, name) { const i = argv.indexOf(name); return i >= 0 ? argv[i + 1] : undefined; }
36
+
37
+ async function main(argv) {
38
+ const cmd = argv[0];
39
+
40
+ if (!cmd || cmd === "help" || cmd === "--help" || cmd === "-h") {
41
+ console.log(HELP);
42
+ return;
43
+ }
44
+
45
+ if (cmd === "init") {
46
+ const agents = [];
47
+ if (flag(argv, "--all-agents")) agents.push("claude", "cursor", "copilot");
48
+ if (flag(argv, "--claude-md") && !agents.includes("claude")) agents.push("claude");
49
+ if (flag(argv, "--cursor") && !agents.includes("cursor")) agents.push("cursor");
50
+ if (flag(argv, "--copilot") && !agents.includes("copilot")) agents.push("copilot");
51
+
52
+ const targetDir = resolve(process.cwd(), opt(argv, "--dir") ?? ".");
53
+ const skill = flag(argv, "--no-skill") ? "none" : flag(argv, "--global") ? "global" : "local";
54
+
55
+ const { steps } = await init(targetDir, {
56
+ skill,
57
+ agents,
58
+ example: !flag(argv, "--no-example"),
59
+ force: flag(argv, "--force"),
60
+ }, ASSETS);
61
+
62
+ console.log(`\n Loop installed into ${targetDir}\n`);
63
+ for (const s of steps) console.log(` ✓ ${s}`);
64
+ console.log(`\n Next:`);
65
+ console.log(` • In a Claude Code chat here: /loop run examples/fix_test.loop`);
66
+ console.log(` • Or describe the work and the agent writes the .loop for you.`);
67
+ console.log(` • Any other agent reads AGENTS.md and can do the same.\n`);
68
+ return;
69
+ }
70
+
71
+ if (["run", "parse", "export", "viz", "show", "ls"].includes(cmd)) {
72
+ console.error(`\`loop ${cmd}\` runs in your agent (the /loop skill) or via the full runtime CLI (@loop/runtime).\nThis package installs Loop — try \`loop init\`. See \`loop help\`.`);
73
+ process.exit(2);
74
+ }
75
+
76
+ console.error(`unknown command: ${cmd}\n`);
77
+ console.log(HELP);
78
+ process.exit(2);
79
+ }
80
+
81
+ main(process.argv.slice(2)).catch((err) => {
82
+ console.error(String(err?.message ?? err));
83
+ process.exit(1);
84
+ });
package/src/init.mjs ADDED
@@ -0,0 +1,100 @@
1
+ // `loop init` — install Loop into a repo so any agent can author + run .loop files.
2
+ // Pure-ish: takes a target dir + options + the assets dir; returns the steps taken.
3
+ // No external deps (node built-ins only) so the published package runs under npx as-is.
4
+ import { readFile, writeFile, mkdir, cp, access } from "node:fs/promises";
5
+ import { homedir } from "node:os";
6
+ import { join, dirname } from "node:path";
7
+
8
+ const MARK_START = "<!-- loop:start (managed by `loop init` — edits between the markers are overwritten) -->";
9
+ const MARK_END = "<!-- loop:end -->";
10
+
11
+ /** Short pointer dropped into an agent's memory file so it knows Loop lives here. */
12
+ export function pointer({ skill }) {
13
+ const run = skill
14
+ ? "run it — in Claude Code via the `/loop` skill (installed at `.claude/skills/loop`), or headless with `loop run <file>`"
15
+ : "run it headless with `loop run <file>`";
16
+ return [
17
+ "## Loop (`.loop`)",
18
+ "",
19
+ "This repo uses **Loop** — a small natural-language DSL for self-correcting, human-gated coding workflows.",
20
+ "When the user asks to set up a loop, turn an epic into a pipeline, or automate a multi-step task, **author a `.loop` file** using the grammar in [`AGENTS.md`](./AGENTS.md), then " + run + ".",
21
+ "Every time you create or change a `.loop`, print its flow so the user can see the shape.",
22
+ ].join("\n");
23
+ }
24
+
25
+ const exists = (p) => access(p).then(() => true, () => false);
26
+
27
+ /** Write `body` into `file`, replacing a prior `loop init` block if present, else appending/creating. */
28
+ async function mergeMarkered(file, body) {
29
+ const block = `${MARK_START}\n${body}\n${MARK_END}`;
30
+ if (await exists(file)) {
31
+ const cur = await readFile(file, "utf8");
32
+ if (cur.includes(MARK_START) && cur.includes(MARK_END)) {
33
+ const next = cur.replace(new RegExp(`${esc(MARK_START)}[\\s\\S]*?${esc(MARK_END)}`), block);
34
+ await writeFile(file, next);
35
+ return "updated";
36
+ }
37
+ await writeFile(file, `${cur.replace(/\s*$/, "")}\n\n${block}\n`);
38
+ return "appended to";
39
+ }
40
+ await mkdir(dirname(file), { recursive: true });
41
+ await writeFile(file, `${block}\n`);
42
+ return "wrote";
43
+ }
44
+ const esc = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
45
+
46
+ async function copyInto(src, dst, { force }) {
47
+ if (!force && (await exists(dst))) return "skipped";
48
+ await mkdir(dirname(dst), { recursive: true });
49
+ await cp(src, dst, { recursive: true });
50
+ return "wrote";
51
+ }
52
+
53
+ /**
54
+ * @param {string} targetDir repo to install into (usually process.cwd())
55
+ * @param {object} opts { skill:"local"|"global"|"none", agents:string[], example:boolean, force:boolean }
56
+ * @param {string} assetsDir this package's assets/ dir (AGENTS.md, skill, examples)
57
+ * @returns {Promise<{steps:string[]}>}
58
+ */
59
+ export async function init(targetDir, opts, assetsDir) {
60
+ const { skill = "local", agents = [], example = true, force = false } = opts;
61
+ const steps = [];
62
+ const withSkill = skill !== "none";
63
+
64
+ // 1. AGENTS.md — the universal language reference (every agent reads it).
65
+ const agentsBody = await readFile(join(assetsDir, "AGENTS.md"), "utf8");
66
+ const verb = await mergeMarkered(join(targetDir, "AGENTS.md"), agentsBody.trim());
67
+ steps.push(`${verb} AGENTS.md (the Loop language reference — any agent)`);
68
+
69
+ // 2. The Claude Code /loop skill.
70
+ if (withSkill) {
71
+ const dst = skill === "global"
72
+ ? join(homedir(), ".claude", "skills", "loop")
73
+ : join(targetDir, ".claude", "skills", "loop");
74
+ const r = await copyInto(join(assetsDir, "skill"), dst, { force });
75
+ steps.push(`${r === "skipped" ? "skipped (exists)" : "wrote"} ${skill === "global" ? "~/.claude/skills/loop" : ".claude/skills/loop"} (the /loop skill)`);
76
+ }
77
+
78
+ // 3. Opt-in per-agent memory pointers.
79
+ const ptr = pointer({ skill: withSkill });
80
+ if (agents.includes("claude")) {
81
+ const v = await mergeMarkered(join(targetDir, "CLAUDE.md"), ptr);
82
+ steps.push(`${v} CLAUDE.md (Claude Code memory)`);
83
+ }
84
+ if (agents.includes("cursor")) {
85
+ const v = await mergeMarkered(join(targetDir, ".cursor", "rules", "loop.md"), ptr);
86
+ steps.push(`${v} .cursor/rules/loop.md (Cursor)`);
87
+ }
88
+ if (agents.includes("copilot")) {
89
+ const v = await mergeMarkered(join(targetDir, ".github", "copilot-instructions.md"), ptr);
90
+ steps.push(`${v} .github/copilot-instructions.md (GitHub Copilot)`);
91
+ }
92
+
93
+ // 4. A starter loop to run.
94
+ if (example) {
95
+ const r = await copyInto(join(assetsDir, "examples", "fix_test.loop"), join(targetDir, "examples", "fix_test.loop"), { force });
96
+ steps.push(`${r === "skipped" ? "skipped (exists)" : "wrote"} examples/fix_test.loop (a starter loop)`);
97
+ }
98
+
99
+ return { steps };
100
+ }