From 5be3f60d5249b22d4fcb304921cb547e3fcc50a5 Mon Sep 17 00:00:00 2001 From: tickets-forge-dev Date: Sun, 5 Jul 2026 00:20:32 -0400 Subject: [PATCH 1/9] seo: complete on-page SEO across loopflow.live docs (30 pages) Ran seo.loop (audit -> fix -> re-audit) over docs/: - add self-referential absolute canonical to all 30 pages - add Open Graph + Twitter card to 26 keyword pages, game.html, workshop.html - add meta descriptions to game.html and workshop.html - add JSON-LD: WebSite (home), WebApplication (playground), BreadcrumbList (keywords) - add robots.txt, sitemap.xml (30 URLs), llms.txt - fix invalid unescaped in use-method.html - repoint 26 keyword pages' broken ../tutorial.html links to ../index.html - add visually-hidden <h1> to game.html Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- .claude/skills/seo-audit/SKILL.md | 119 +++++++++++++++ .../skills/seo-audit/references/checklist.md | 140 ++++++++++++++++++ docs/game.html | 13 ++ docs/index.html | 5 + docs/keywords/after-n-tries.html | 16 +- docs/keywords/allow.html | 16 +- docs/keywords/also.html | 16 +- docs/keywords/done-when.html | 16 +- docs/keywords/each-cycle.html | 16 +- docs/keywords/flow.html | 16 +- docs/keywords/for-each.html | 16 +- docs/keywords/git.html | 16 +- docs/keywords/goal.html | 16 +- docs/keywords/human-gates.html | 16 +- docs/keywords/index.html | 20 ++- docs/keywords/look-at.html | 16 +- docs/keywords/loop.html | 16 +- docs/keywords/models.html | 16 +- docs/keywords/notify.html | 16 +- docs/keywords/pipeline.html | 16 +- docs/keywords/plan-from.html | 16 +- docs/keywords/reflect.html | 16 +- docs/keywords/remember-in.html | 16 +- docs/keywords/run.html | 16 +- docs/keywords/schedule.html | 16 +- docs/keywords/stage.html | 16 +- docs/keywords/target.html | 16 +- docs/keywords/use-method.html | 18 ++- docs/keywords/use-skills.html | 16 +- docs/keywords/when.html | 16 +- docs/llms.txt | 37 +++++ docs/playground.html | 7 + docs/robots.txt | 4 + docs/seo.memory.md | 28 ++++ docs/sitemap.xml | 33 +++++ docs/workshop.html | 12 ++ seo.loop | 32 ++++ 37 files changed, 797 insertions(+), 55 deletions(-) create mode 100644 .claude/skills/seo-audit/SKILL.md create mode 100644 .claude/skills/seo-audit/references/checklist.md create mode 100644 docs/llms.txt create mode 100644 docs/robots.txt create mode 100644 docs/seo.memory.md create mode 100644 docs/sitemap.xml create mode 100644 seo.loop diff --git a/.claude/skills/seo-audit/SKILL.md b/.claude/skills/seo-audit/SKILL.md new file mode 100644 index 0000000..493fd14 --- /dev/null +++ b/.claude/skills/seo-audit/SKILL.md @@ -0,0 +1,119 @@ +--- +name: seo-audit +description: Audit and improve on-page SEO for web pages, docs sites, and marketing pages. Use whenever the user wants an SEO review or audit, wants to check or fix title tags / meta descriptions / Open Graph / Twitter cards / canonical URLs / structured data (JSON-LD) / robots / sitemap / heading structure / image alt text, asks "why isn't this page ranking / showing a preview card", wants to optimize a page for search or social sharing, or mentions SEO, meta tags, OG tags, rich results, or search snippets — even if they don't say the word "audit". Works on local source files (HTML, JSX/TSX, Markdown, Astro/Next/Vite) or a live URL. Not for off-page SEO (backlinks, ad campaigns) or keyword-volume research. +--- + +# On-page SEO audit + +Review a page (or a set of pages) against on-page SEO best practices, report what's +wrong in priority order, and — when the user wants — fix it in the source files. + +The point is not to produce a checklist for its own sake. Search engines and social +platforms read a page's `<head>` and semantic HTML to decide how to index it and how to +render its preview card. When those signals are missing or wrong, the page still "works" +for humans but is invisible or ugly to crawlers. Your job is to find that gap and close it. + +## Decide the target first + +Two modes — pick based on what the user gives you: + +- **Source mode (default when working in a repo):** audit the files that produce the page. + This is what the user usually wants when the pages live in this repo, because the fix + lands in code they can commit. Find where `<head>` / metadata is set — this varies by + stack, so look before assuming: + - Static HTML → the `<head>` in the `.html` file. + - Next.js → `metadata` exports / `<Head>` / `generateMetadata` in `app/` or `pages/`. + - Astro → frontmatter + `<head>` in layout `.astro` files. + - Vite/plain SPA → `index.html` plus any runtime `document.title` / meta injection. + - Markdown docs (MkDocs, Docusaurus, VitePress, Jekyll) → frontmatter + the theme's + head template. Per-page `title`/`description` usually live in frontmatter. + Grep for `og:`, `twitter:`, `canonical`, `application/ld+json`, `<title`, `meta name="description"` + to locate every place metadata is set — there is often more than one. +- **Live mode:** the user gives a URL, or the rendering is dynamic and you need to see the + final DOM. Fetch it with `WebFetch`, or drive Chrome (the `mcp__claude-in-chrome__*` + tools) when the head is populated by client-side JS that `WebFetch` won't execute. Read + the rendered `<head>`. Note in the report that you audited rendered output, not source. + +If the user hasn't said which, infer from context (a repo path → source; a URL → live) and +state which mode you chose in one line. Don't stall on the choice. + +## What to check + +Go through these. For each, report the current value (or "missing"), whether it's OK, and +what to change. Read `references/checklist.md` for the full detail on any item — thresholds, +common mistakes, and exactly what good looks like. The high-signal ones, roughly in order +of how often they matter: + +1. **`<title>`** — present, unique per page, ~50–60 chars, front-loads the primary term. +2. **`<meta name="description">`** — present, ~120–160 chars, compelling, not duplicated + across pages. Missing/duplicate descriptions are the single most common real problem. +3. **Open Graph** — `og:title`, `og:description`, `og:image` (absolute URL, ~1200×630), + `og:url`, `og:type`. This is what LinkedIn/Slack/Facebook show. A missing `og:image` + is why a shared link looks blank. +4. **Twitter/X card** — `twitter:card` (usually `summary_large_image`), plus title/desc/image. +5. **Canonical** — `<link rel="canonical">` with an absolute URL, to avoid duplicate-content + splitting between www/non-www, trailing-slash, and query-param variants. +6. **Headings** — exactly one `<h1>`, no skipped levels (h1→h3), headings describe content + not styling. +7. **Image `alt`** — every meaningful `<img>` has descriptive alt text; decorative images + have empty `alt=""`. +8. **Structured data** — JSON-LD (`application/ld+json`) appropriate to the page type + (Article, Product, Organization, BreadcrumbList, FAQPage). Validate the shape. +9. **`robots`** — no accidental `noindex`/`nofollow` on pages that should rank; a sensible + `<meta name="robots">` where needed. +10. **Crawlability** — `robots.txt` and `sitemap.xml` exist and are referenced; internal + links use real `<a href>`; important content isn't hidden behind JS-only rendering. +11. **Technical hygiene** — `<html lang>` set, one viewport meta, HTTPS, no broken canonical + or OG URLs, reasonable page-load weight. + +Don't invent problems to pad the report. If a page is in good shape, say so — a short +"these 9 things are correct, here are the 2 that aren't" is more useful than a wall of green +checkmarks. + +## Report format + +Lead with the fixes that matter. Use this shape: + +``` +# SEO audit — <page or URL> (<source|live> mode) + +## Critical (breaks indexing or sharing) +- <issue> — <why it matters> — <exact fix, with file:line if source mode> + +## Recommended (real improvement, not urgent) +- ... + +## Passing +- <one line each for the checks that are already correct> +``` + +- **Critical** = the page won't be indexed correctly or its share card is broken (missing + title, `noindex` by accident, no og:image, broken canonical). +- **Recommended** = genuine improvements (thin description, missing JSON-LD, h1 issues). +- Every fix must be **specific**: the actual tag to add and where, not "improve your meta + description". In source mode, cite `file:line`. Prefer showing the exact snippet to paste. + +## Applying fixes + +Only edit files when the user asks you to fix things (or approves the audit's fixes). Then: + +- Make the smallest change that resolves each issue; match the file's existing style and the + framework's idiom (e.g. Next's `metadata` export, not a raw `<head>` tag, in an app-router + project). +- Use **absolute** URLs for `og:image`, `og:url`, and `canonical` — relative URLs silently + break when the page is scraped off-domain. If you don't know the production origin, find it + (existing tags, `package.json` homepage, CNAME, config) or ask rather than guessing. +- After editing, re-run the relevant checks so the report reflects reality, and show a diff. + +## Verifying + +Recommend the user confirm share cards with the platform validators (these re-scrape the +live URL, so they only work after deploy): opengraph.xyz, LinkedIn Post Inspector, +X/Twitter Card Validator, and Google's Rich Results Test for structured data. For local +verification, re-read the rendered `<head>` (live mode) or re-grep the source (source mode). +``` +``` + +Keep the audit proportional to the ask: one page → tight focused report; "audit the whole +site" → sample the templates that generate the pages (layout, per-type page components) +since fixing a template fixes every page it renders, and call out which pages inherit each fix. diff --git a/.claude/skills/seo-audit/references/checklist.md b/.claude/skills/seo-audit/references/checklist.md new file mode 100644 index 0000000..d33c687 --- /dev/null +++ b/.claude/skills/seo-audit/references/checklist.md @@ -0,0 +1,140 @@ +# On-page SEO checklist — full detail + +Read this when you need the precise threshold, the common failure mode, or a copy-paste +example for a given item. The SKILL.md has the summary; this has the specifics. + +## Table of contents +1. Title tag +2. Meta description +3. Open Graph +4. Twitter / X card +5. Canonical URL +6. Headings +7. Image alt text +8. Structured data (JSON-LD) +9. Robots directives +10. Crawlability (robots.txt, sitemap, links) +11. Technical hygiene +12. Copy-paste starter block + +--- + +## 1. Title tag +- **Good:** unique per page, ~50–60 characters (Google truncates around 580px ≈ 60 chars), + primary keyword/topic near the front, brand at the end (`Primary Topic — Brand`). +- **Bad:** same title on every page, empty, >70 chars (truncated in results), keyword-stuffed, + or set only via JS so crawlers that don't run JS miss it. +- Only one `<title>` per page. In SPAs, make sure the title is set before first paint or + server-rendered, not just updated on route change. + +## 2. Meta description +- **Good:** 120–160 characters, reads like ad copy, describes what the page delivers, unique + per page, includes the term a searcher would use. +- **Bad:** missing (Google auto-generates a worse one), duplicated across pages (the most + common real SEO defect), truncated mid-word, or just the first sentence of body text. +- Not a ranking factor directly, but drives click-through from the results page, which is. + +## 3. Open Graph (`og:`) +Required for a rich share card on LinkedIn, Facebook, Slack, Discord, iMessage: +- `og:title` — can differ from `<title>`; optimize for the share context. +- `og:description` — 2–4 sentences. +- `og:image` — **absolute** URL, ideally 1200×630 (1.91:1), under ~5MB, PNG/JPG. This is the + single most impactful tag for social — a missing or relative `og:image` is why a shared link + renders as a blank/text-only card. +- `og:url` — the canonical absolute URL of the page. +- `og:type` — `website` for home/landing, `article` for posts. +- Optional but nice: `og:site_name`, `og:image:alt`, `og:locale`. + +## 4. Twitter / X card +- `twitter:card` — `summary_large_image` for a big image, `summary` for a small one. +- `twitter:title`, `twitter:description`, `twitter:image` — X falls back to OG tags for + most fields, so you often only need `twitter:card` if OG is complete. Verify rather than + assuming; add `twitter:image` explicitly if the OG image isn't picked up. +- Optional: `twitter:site` / `twitter:creator` (@handles). + +## 5. Canonical URL +- `<link rel="canonical" href="https://example.com/page">` — absolute, self-referential on + the primary version of the page. +- Prevents duplicate-content dilution across `http/https`, `www/non-www`, trailing slash, + and tracking-param variants (`?utm_...`). +- **Bad:** canonical pointing to the wrong page, to a relative URL, to a `noindex` page, or + every page canonicalizing to the homepage (a classic accidental de-indexing). + +## 6. Headings +- Exactly one `<h1>`, describing the page's main topic. +- Don't skip levels (h1 → h2 → h3, not h1 → h4). Screen readers and crawlers use the outline. +- Headings should describe content, not be chosen for their font size — use CSS for styling. + +## 7. Image alt text +- Every meaningful `<img>` needs `alt` describing the image's content/function. +- Purely decorative images: `alt=""` (empty, not missing) so assistive tech skips them. +- **Bad:** `alt="image"`, `alt="logo logo logo"`, filename dumped as alt, or no alt attribute + at all (fails accessibility and loses image-search traffic). + +## 8. Structured data (JSON-LD) +- Embed as `<script type="application/ld+json">` in the head or body. +- Match the schema.org type to the page: `Article`/`BlogPosting`, `Product` + `Offer`, + `Organization`, `WebSite` (+ `SearchAction` for a sitelinks search box), `BreadcrumbList`, + `FAQPage`, `HowTo`. +- Required fields vary by type — validate the shape (all required properties present, correct + nesting) and confirm it matches visible page content (Google penalizes mismatched markup). +- Verify with Google's Rich Results Test after deploy. + +## 9. Robots directives +- Check no page that should rank carries `<meta name="robots" content="noindex">` or + `nofollow` by accident — a staging default that shipped to prod is a common cause of "my + pages vanished from Google." +- Use `noindex` deliberately on thank-you pages, filtered/faceted URLs, internal search results. +- `X-Robots-Tag` HTTP header can also set this — in live mode check response headers too. + +## 10. Crawlability +- **robots.txt** at the domain root: doesn't accidentally `Disallow: /`, and references the + sitemap (`Sitemap: https://example.com/sitemap.xml`). +- **sitemap.xml**: exists, lists canonical URLs, valid XML, submitted in Search Console. +- **Internal links** use real `<a href>` (crawlers follow those, not `onclick` divs). +- **Content** important for ranking should be in the initial HTML, not injected only after a + client-side fetch — if it's live mode, compare `WebFetch` output (no JS) against the + Chrome-rendered DOM to see what a non-JS crawler misses. + +## 11. Technical hygiene +- `<html lang="en">` (or correct locale) set. +- Exactly one `<meta name="viewport" content="width=device-width, initial-scale=1">`. +- Served over HTTPS; no mixed content. +- No duplicate/conflicting meta tags (two descriptions, two canonicals). +- Reasonable performance — Core Web Vitals (LCP, CLS, INP) influence ranking; flag obviously + heavy pages, but deep perf work is its own task. + +## 12. Copy-paste starter block +A complete, correct head to diff a page against (replace values; keep URLs absolute): + +```html +<title>Primary Topic — Brand + + + + + + + + + + + + + + + + + + + + + +``` diff --git a/docs/game.html b/docs/game.html index fe47b7e..ccfd6f4 100644 --- a/docs/game.html +++ b/docs/game.html @@ -5,6 +5,18 @@ LoopFlow Lab — learn loops by building them + + + + + + + + + + + + @@ -223,6 +235,7 @@ +

LoopFlow Lab — learn loop engineering by building loops

LoopFlow Studio
diff --git a/docs/index.html b/docs/index.html index 6b132c0..037788d 100644 --- a/docs/index.html +++ b/docs/index.html @@ -11,10 +11,15 @@ + + + diff --git a/docs/keywords/after-n-tries.html b/docs/keywords/after-n-tries.html index 2c3ada9..c7aa09a 100644 --- a/docs/keywords/after-n-tries.html +++ b/docs/keywords/after-n-tries.html @@ -1,6 +1,18 @@ after N tries (thrash guard) — LoopFlow keyword + + + + + + + + + + + + @@ -12,7 +24,7 @@
LoopFlow
- Tutorial + Tutorial Workshop Keywords 🎮 LoopFlow Lab @@ -42,5 +54,5 @@

How it runs

The order is the engine's, not yours: attempts is checked before fail, so the thrash guard always wins once you hit the limit.

Related

-
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
+
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
\ No newline at end of file diff --git a/docs/keywords/allow.html b/docs/keywords/allow.html index 98adcb0..1d65309 100644 --- a/docs/keywords/allow.html +++ b/docs/keywords/allow.html @@ -1,6 +1,18 @@ allow / ask me before — LoopFlow keyword + + + + + + + + + + + + @@ -12,7 +24,7 @@
LoopFlow
- Tutorial + Tutorial Workshop Keywords 🎮 LoopFlow Lab @@ -30,5 +42,5 @@

Example

Related

-
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
+
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
\ No newline at end of file diff --git a/docs/keywords/also.html b/docs/keywords/also.html index 0ac7b07..603f9e6 100644 --- a/docs/keywords/also.html +++ b/docs/keywords/also.html @@ -1,6 +1,18 @@ also — LoopFlow keyword + + + + + + + + + + + + @@ -12,7 +24,7 @@
LoopFlow
- Tutorial + Tutorial Workshop Keywords 🎮 LoopFlow Lab @@ -30,5 +42,5 @@

Example

Related

-
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
+
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
\ No newline at end of file diff --git a/docs/keywords/done-when.html b/docs/keywords/done-when.html index bfaad2a..8021a39 100644 --- a/docs/keywords/done-when.html +++ b/docs/keywords/done-when.html @@ -1,6 +1,18 @@ done when — LoopFlow keyword + + + + + + + + + + + + @@ -12,7 +24,7 @@
LoopFlow
- Tutorial + Tutorial Workshop Keywords 🎮 LoopFlow Lab @@ -33,5 +45,5 @@

Example

Related

-
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
+
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
\ No newline at end of file diff --git a/docs/keywords/each-cycle.html b/docs/keywords/each-cycle.html index 22b2b2e..e3b1bb1 100644 --- a/docs/keywords/each-cycle.html +++ b/docs/keywords/each-cycle.html @@ -1,6 +1,18 @@ each cycle — LoopFlow keyword + + + + + + + + + + + + @@ -12,7 +24,7 @@
LoopFlow
- Tutorial + Tutorial Workshop Keywords 🎮 LoopFlow Lab @@ -43,5 +55,5 @@

How it runs

Every cycle runs plan → act → observe; the done when check decides — pass → stop, fail → reflect into the next plan.

Related

-
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
+
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
\ No newline at end of file diff --git a/docs/keywords/flow.html b/docs/keywords/flow.html index 9fe5a9e..996133f 100644 --- a/docs/keywords/flow.html +++ b/docs/keywords/flow.html @@ -1,6 +1,18 @@ flow — LoopFlow keyword + + + + + + + + + + + + @@ -12,7 +24,7 @@
LoopFlow
- Tutorial + Tutorial Workshop Keywords 🎮 LoopFlow Lab @@ -44,5 +56,5 @@

How it runs

A flow chains separate .loop files; after each, a short text summary carries into the next as context.

Related

-
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
+
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
\ No newline at end of file diff --git a/docs/keywords/for-each.html b/docs/keywords/for-each.html index 02e20e8..64ce85c 100644 --- a/docs/keywords/for-each.html +++ b/docs/keywords/for-each.html @@ -1,6 +1,18 @@ for each — LoopFlow keyword + + + + + + + + + + + + @@ -12,7 +24,7 @@
LoopFlow
- Tutorial + Tutorial Workshop Keywords 🎮 LoopFlow Lab @@ -49,5 +61,5 @@

How it runs

for each is dynamic fan-out: a planning step discovers the items, then the same template runs once per item.

Related

-
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
+
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
\ No newline at end of file diff --git a/docs/keywords/git.html b/docs/keywords/git.html index df1e3b7..5aba4c9 100644 --- a/docs/keywords/git.html +++ b/docs/keywords/git.html @@ -1,6 +1,18 @@ git: — LoopFlow keyword + + + + + + + + + + + + @@ -12,7 +24,7 @@
LoopFlow
- Tutorial + Tutorial Workshop Keywords 🎮 LoopFlow Lab @@ -47,5 +59,5 @@

How it runs

Three layers, each refining the one above. The protected-branch rule sits outside all of them: pushing to main/master is always refused.

Related

-
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
+
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
\ No newline at end of file diff --git a/docs/keywords/goal.html b/docs/keywords/goal.html index e954a3a..8332226 100644 --- a/docs/keywords/goal.html +++ b/docs/keywords/goal.html @@ -1,6 +1,18 @@ goal — LoopFlow keyword + + + + + + + + + + + + @@ -12,7 +24,7 @@
LoopFlow
- Tutorial + Tutorial Workshop Keywords 🎮 LoopFlow Lab @@ -30,5 +42,5 @@

Example

Related

-
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
+
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
\ No newline at end of file diff --git a/docs/keywords/human-gates.html b/docs/keywords/human-gates.html index 4774359..5d37ad6 100644 --- a/docs/keywords/human-gates.html +++ b/docs/keywords/human-gates.html @@ -1,6 +1,18 @@ human gates — LoopFlow keyword + + + + + + + + + + + + @@ -12,7 +24,7 @@
LoopFlow
- Tutorial + Tutorial Workshop Keywords 🎮 LoopFlow Lab @@ -35,5 +47,5 @@

Example

Related

-
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
+
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
\ No newline at end of file diff --git a/docs/keywords/index.html b/docs/keywords/index.html index 687c741..ba4e7ac 100644 --- a/docs/keywords/index.html +++ b/docs/keywords/index.html @@ -1,6 +1,18 @@ Keywords — LoopFlow reference + + + + + + + + + + + + @@ -12,16 +24,16 @@
-
LoopFlow / Keywords
+
LoopFlow / Keywords

Keywords

Every construct in the LoopFlow language — one page each, with syntax, what it does, examples, and a diagram where it helps.
-

Learning the language top-to-bottom? Read the tutorial. This is the by-keyword reference.

+

Learning the language top-to-bottom? Read the tutorial. This is the by-keyword reference.

Core syntax — the five decisionsThe engine. Objective, context, actions, verification, stopping — plus the cycle that drives them, and where a human steps in.
The five decisions
@@ -37,5 +49,5 @@

Keywords

Ops & reuse
-
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
+
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
\ No newline at end of file diff --git a/docs/keywords/look-at.html b/docs/keywords/look-at.html index e5e2895..b0cc622 100644 --- a/docs/keywords/look-at.html +++ b/docs/keywords/look-at.html @@ -1,6 +1,18 @@ look at — LoopFlow keyword + + + + + + + + + + + + @@ -12,7 +24,7 @@
LoopFlow
- Tutorial + Tutorial Workshop Keywords 🎮 LoopFlow Lab @@ -30,5 +42,5 @@

Example

Related

-
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
+
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
\ No newline at end of file diff --git a/docs/keywords/loop.html b/docs/keywords/loop.html index 7ebb783..4bb50d7 100644 --- a/docs/keywords/loop.html +++ b/docs/keywords/loop.html @@ -1,6 +1,18 @@ loop — LoopFlow keyword + + + + + + + + + + + + @@ -12,7 +24,7 @@
LoopFlow
- Tutorial + Tutorial Workshop Keywords 🎮 LoopFlow Lab @@ -46,5 +58,5 @@

How it runs

Every cycle runs plan → act → observe; the done when check decides — pass → stop, fail → reflect into the next plan.

Related

-
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
+
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
\ No newline at end of file diff --git a/docs/keywords/models.html b/docs/keywords/models.html index e396c37..715b4d6 100644 --- a/docs/keywords/models.html +++ b/docs/keywords/models.html @@ -1,6 +1,18 @@ models: — LoopFlow keyword + + + + + + + + + + + + @@ -12,7 +24,7 @@
LoopFlow
- Tutorial + Tutorial Workshop Keywords 🎮 LoopFlow Lab @@ -41,5 +53,5 @@

How it runs

Cheap model for the thinking phases, strong model for writing code. The end-of-run summary shows the call mix per tier.

Related

-
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
+
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
\ No newline at end of file diff --git a/docs/keywords/notify.html b/docs/keywords/notify.html index 876e376..bf80e46 100644 --- a/docs/keywords/notify.html +++ b/docs/keywords/notify.html @@ -1,6 +1,18 @@ notify — LoopFlow keyword + + + + + + + + + + + + @@ -12,7 +24,7 @@
LoopFlow
- Tutorial + Tutorial Workshop Keywords 🎮 LoopFlow Lab @@ -31,5 +43,5 @@

Example

Related

-
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
+
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
\ No newline at end of file diff --git a/docs/keywords/pipeline.html b/docs/keywords/pipeline.html index d26ed6d..383abbc 100644 --- a/docs/keywords/pipeline.html +++ b/docs/keywords/pipeline.html @@ -1,6 +1,18 @@ pipeline — LoopFlow keyword + + + + + + + + + + + + @@ -12,7 +24,7 @@
LoopFlow
- Tutorial + Tutorial Workshop Keywords 🎮 LoopFlow Lab @@ -46,5 +58,5 @@

How it runs

An epic → a pipeline, each story → a stage; stages run in order with their own checks and gates.

Related

-
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
+
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
\ No newline at end of file diff --git a/docs/keywords/plan-from.html b/docs/keywords/plan-from.html index 664b3bd..76794d3 100644 --- a/docs/keywords/plan-from.html +++ b/docs/keywords/plan-from.html @@ -1,6 +1,18 @@ plan from — LoopFlow keyword + + + + + + + + + + + + @@ -12,7 +24,7 @@
LoopFlow
- Tutorial + Tutorial Workshop Keywords 🎮 LoopFlow Lab @@ -34,5 +46,5 @@

Example

Related

-
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
+
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
\ No newline at end of file diff --git a/docs/keywords/reflect.html b/docs/keywords/reflect.html index 5eb8f0f..0f4feb6 100644 --- a/docs/keywords/reflect.html +++ b/docs/keywords/reflect.html @@ -1,6 +1,18 @@ reflect — LoopFlow keyword + + + + + + + + + + + + @@ -12,7 +24,7 @@
LoopFlow
- Tutorial + Tutorial Workshop Keywords 🎮 LoopFlow Lab @@ -42,5 +54,5 @@

How it runs

Every cycle runs plan → act → observe; the done when check decides — pass → stop, fail → reflect into the next plan.

Related

-
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
+
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
\ No newline at end of file diff --git a/docs/keywords/remember-in.html b/docs/keywords/remember-in.html index 94f54d3..59721b8 100644 --- a/docs/keywords/remember-in.html +++ b/docs/keywords/remember-in.html @@ -1,6 +1,18 @@ remember in — LoopFlow keyword + + + + + + + + + + + + @@ -12,7 +24,7 @@
LoopFlow
- Tutorial + Tutorial Workshop Keywords 🎮 LoopFlow Lab @@ -35,5 +47,5 @@

Example

Related

-
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
+
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
diff --git a/docs/keywords/run.html b/docs/keywords/run.html index 992ca7c..fd17fa9 100644 --- a/docs/keywords/run.html +++ b/docs/keywords/run.html @@ -1,6 +1,18 @@ run / then run — LoopFlow keyword + + + + + + + + + + + + @@ -12,7 +24,7 @@
LoopFlow
- Tutorial + Tutorial Workshop Keywords 🎮 LoopFlow Lab @@ -43,5 +55,5 @@

How it runs

A flow chains separate .loop files; after each, a short text summary carries into the next as context.

Related

-
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
+
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
\ No newline at end of file diff --git a/docs/keywords/schedule.html b/docs/keywords/schedule.html index ac9d1e2..e249765 100644 --- a/docs/keywords/schedule.html +++ b/docs/keywords/schedule.html @@ -1,6 +1,18 @@ schedule — LoopFlow keyword + + + + + + + + + + + + @@ -12,7 +24,7 @@
LoopFlow
- Tutorial + Tutorial Workshop Keywords 🎮 LoopFlow Lab @@ -32,5 +44,5 @@

Example

Related

-
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
+
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
\ No newline at end of file diff --git a/docs/keywords/stage.html b/docs/keywords/stage.html index eadeece..4517884 100644 --- a/docs/keywords/stage.html +++ b/docs/keywords/stage.html @@ -1,6 +1,18 @@ stage — LoopFlow keyword + + + + + + + + + + + + @@ -12,7 +24,7 @@
LoopFlow
- Tutorial + Tutorial Workshop Keywords 🎮 LoopFlow Lab @@ -35,5 +47,5 @@

Example

Related

-
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
+
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
\ No newline at end of file diff --git a/docs/keywords/target.html b/docs/keywords/target.html index 93b0912..ec9fdc6 100644 --- a/docs/keywords/target.html +++ b/docs/keywords/target.html @@ -1,6 +1,18 @@ target — LoopFlow keyword + + + + + + + + + + + + @@ -12,7 +24,7 @@
LoopFlow
- Tutorial + Tutorial Workshop Keywords 🎮 LoopFlow Lab @@ -31,5 +43,5 @@

Example

Related

-
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
+
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
\ No newline at end of file diff --git a/docs/keywords/use-method.html b/docs/keywords/use-method.html index fdb9e78..f017331 100644 --- a/docs/keywords/use-method.html +++ b/docs/keywords/use-method.html @@ -1,6 +1,18 @@ -use the <X> method — LoopFlow keyword +use the <X> method — LoopFlow keyword + + + + + + + + + + + + @@ -12,7 +24,7 @@
LoopFlow
- Tutorial + Tutorial Workshop Keywords 🎮 LoopFlow Lab @@ -32,5 +44,5 @@

Example

Related

-
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
+
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
\ No newline at end of file diff --git a/docs/keywords/use-skills.html b/docs/keywords/use-skills.html index 6364777..b50e17f 100644 --- a/docs/keywords/use-skills.html +++ b/docs/keywords/use-skills.html @@ -1,6 +1,18 @@ use skills — LoopFlow keyword + + + + + + + + + + + + @@ -12,7 +24,7 @@
LoopFlow
- Tutorial + Tutorial Workshop Keywords 🎮 LoopFlow Lab @@ -35,5 +47,5 @@

Example

Related

-
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
+
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
diff --git a/docs/keywords/when.html b/docs/keywords/when.html index 60fbe55..13e46a8 100644 --- a/docs/keywords/when.html +++ b/docs/keywords/when.html @@ -1,6 +1,18 @@ when … (transitions) — LoopFlow keyword + + + + + + + + + + + + @@ -12,7 +24,7 @@
LoopFlow
- Tutorial + Tutorial Workshop Keywords 🎮 LoopFlow Lab @@ -46,5 +58,5 @@

How it runs

The order is the engine's, not yours: attempts is checked before fail, so the thrash guard always wins once you hit the limit.

Related

-
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
+
LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
\ No newline at end of file diff --git a/docs/llms.txt b/docs/llms.txt new file mode 100644 index 0000000..34d2ac1 --- /dev/null +++ b/docs/llms.txt @@ -0,0 +1,37 @@ +# LoopFlow + +> LoopFlow is an open, natural-language DSL for **loop engineering**: you describe a +> self-correcting, human-gated AI coding workflow in plain English — its goal, the context +> it may read, the actions it may take, how it verifies itself (`done when`), and where a +> human steps in — then run it until the check is green. A `.loop` file turns "babysitting +> the agent" into a scoped, verifiable, repeatable loop. + +Use LoopFlow when a coding task is **repeatable and verifiable**: a bug fixed by a failing +test, a refactor gated by a check, an epic broken into stories, a migration with a +verification step. A loop plans, acts, observes its own `done when` check, reflects on +failure, and stops only when the goal is met or a thrash guard fires. + +Key concepts (each has a reference page under /keywords/): +- goal — what "done" means, in plain language +- done when — the predicate the loop uses to verify itself (a test, a command, a review skill) +- look at — the context the loop reads before acting +- each cycle — the repeated plan → act → observe steps +- reflect — turning a failure into context for the next plan (the back-edge) +- after N tries — the thrash guard that stops a stuck loop +- pipeline / stage — an epic as a sequence of gated stages +- flow / for each — chaining whole .loop files, or running a template per plan item +- human gates — where a person approves the plan, a stage, or the stop + +## Docs +- [Tutorial (home)](https://loopflow.live/): what LoopFlow is and why loops beat one-shot prompts +- [Playground](https://loopflow.live/playground.html): type a .loop, see its shape live in-browser +- [Workshop](https://loopflow.live/workshop.html): build a loop step by step +- [LoopFlow Lab](https://loopflow.live/game.html): learn loop engineering by playing +- [Keyword reference](https://loopflow.live/keywords/): every word in the DSL, one page each + +## Run it +- In Claude Code: the `/loopflow` skill authors and runs `.loop` files in-session. +- Headless: `loop-run run .loop`. + +## Source +- GitHub: https://github.com/tickets-forge-dev/loop-lang (grammar in AGENTS.md, manual in docs/MANUAL.md) diff --git a/docs/playground.html b/docs/playground.html index 51c9af0..2c514a4 100644 --- a/docs/playground.html +++ b/docs/playground.html @@ -11,8 +11,15 @@ + + + + + diff --git a/docs/robots.txt b/docs/robots.txt new file mode 100644 index 0000000..895dac2 --- /dev/null +++ b/docs/robots.txt @@ -0,0 +1,4 @@ +User-agent: * +Allow: / + +Sitemap: https://loopflow.live/sitemap.xml diff --git a/docs/seo.memory.md b/docs/seo.memory.md new file mode 100644 index 0000000..79d8580 --- /dev/null +++ b/docs/seo.memory.md @@ -0,0 +1,28 @@ +# seo.loop — memory + +Cross-run lessons for the on-page SEO loop over the loopflow.live docs site. + +## 2026-07-05 — PASSED (2 cycles) + +- **Goal met:** all 30 docs pages have unique title + description, full OG + Twitter card, + self-referential absolute canonical, one `

`, and valid JSON-LD; `robots.txt`, + `sitemap.xml` (30 URLs), and `llms.txt` added. +- **Starting state:** only `index.html` + `playground.html` had OG/Twitter; nothing had a + canonical; keyword pages were title+desc only; `game.html` had no description and no `

`. +- **What worked:** the 26 keyword pages are structurally uniform, so a Python script + (`scratchpad/inject_seo.py`) injected canonical/OG/Twitter/BreadcrumbList by reusing each + page's own `` + description — far faster than 26 hand edits. Keep this pattern for + any future bulk head-tag change. +- **Gotchas found by the audit:** + - `keywords/use-method.html` had an unescaped `<X>` inside `<title>` (invalid HTML, broke + title parsing). Escaped to `<X>`. Check new keyword pages whose name contains `<…>`. + - Keyword pages linked nav + footer to a non-existent `../tutorial.html` (the homepage is + `index.html`, which top-level pages already link as "Tutorial"). Repointed to + `../index.html`. If a `tutorial.html` is ever added at deploy, revisit. + - `game.html` is a JS game with no natural `<h1>`; added a visually-hidden keyword-rich + `<h1>` after `<body>` rather than disturbing the game UI. +- **Still open (bigger levers, out of this loop's scope):** keyword pages are thin + (one-sentence bodies) — expanding them into real reference content is the biggest ranking + lever. Per-page OG images would lift share CTR. Both are good candidates for their own loop. +- **Next run:** re-audit after any new pages; the script is idempotent (skips pages that + already have a canonical), so re-running is safe. diff --git a/docs/sitemap.xml b/docs/sitemap.xml new file mode 100644 index 0000000..54fcd80 --- /dev/null +++ b/docs/sitemap.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="UTF-8"?> +<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> + <url><loc>https://loopflow.live/game.html</loc></url> + <url><loc>https://loopflow.live/</loc></url> + <url><loc>https://loopflow.live/playground.html</loc></url> + <url><loc>https://loopflow.live/workshop.html</loc></url> + <url><loc>https://loopflow.live/keywords/after-n-tries.html</loc></url> + <url><loc>https://loopflow.live/keywords/allow.html</loc></url> + <url><loc>https://loopflow.live/keywords/also.html</loc></url> + <url><loc>https://loopflow.live/keywords/done-when.html</loc></url> + <url><loc>https://loopflow.live/keywords/each-cycle.html</loc></url> + <url><loc>https://loopflow.live/keywords/flow.html</loc></url> + <url><loc>https://loopflow.live/keywords/for-each.html</loc></url> + <url><loc>https://loopflow.live/keywords/git.html</loc></url> + <url><loc>https://loopflow.live/keywords/goal.html</loc></url> + <url><loc>https://loopflow.live/keywords/human-gates.html</loc></url> + <url><loc>https://loopflow.live/keywords/</loc></url> + <url><loc>https://loopflow.live/keywords/look-at.html</loc></url> + <url><loc>https://loopflow.live/keywords/loop.html</loc></url> + <url><loc>https://loopflow.live/keywords/models.html</loc></url> + <url><loc>https://loopflow.live/keywords/notify.html</loc></url> + <url><loc>https://loopflow.live/keywords/pipeline.html</loc></url> + <url><loc>https://loopflow.live/keywords/plan-from.html</loc></url> + <url><loc>https://loopflow.live/keywords/reflect.html</loc></url> + <url><loc>https://loopflow.live/keywords/remember-in.html</loc></url> + <url><loc>https://loopflow.live/keywords/run.html</loc></url> + <url><loc>https://loopflow.live/keywords/schedule.html</loc></url> + <url><loc>https://loopflow.live/keywords/stage.html</loc></url> + <url><loc>https://loopflow.live/keywords/target.html</loc></url> + <url><loc>https://loopflow.live/keywords/use-method.html</loc></url> + <url><loc>https://loopflow.live/keywords/use-skills.html</loc></url> + <url><loc>https://loopflow.live/keywords/when.html</loc></url> +</urlset> diff --git a/docs/workshop.html b/docs/workshop.html index 984dc0a..1a8197b 100644 --- a/docs/workshop.html +++ b/docs/workshop.html @@ -5,6 +5,18 @@ <link rel="icon" type="image/svg+xml" href="/gyro-icon.svg" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <title>LoopFlow — the workshop + + + + + + + + + + + + diff --git a/seo.loop b/seo.loop new file mode 100644 index 0000000..80cd884 --- /dev/null +++ b/seo.loop @@ -0,0 +1,32 @@ +# seo.loop — self-correcting on-page SEO for the loopflow.live docs site. +# Runs the seo-audit skill to both DO the work and CHECK it: audit → fix → re-audit, +# looping until the audit finds no Critical issues on any page. + +loop "seo: loopflow.live docs": + # ── Contract: the finish line, and how it's verified ────────────────────────── + goal: every public page under docs/ has complete, unique on-page SEO — a unique + and meta description, a full Open Graph + Twitter card with an + absolute og:image, a self-referential canonical URL, exactly one <h1>, + alt text on meaningful images, and valid JSON-LD. + + done when the skill "seo-audit" approves + the bar: zero Critical issues on any audited page; every og:image / og:url / + canonical is an absolute https URL; titles and meta descriptions are + unique per page (no duplicates across the site). + + # ── Boundaries: what it may read, and how much power it has ─────────────────── + look at: docs/index.html, docs/game.html, docs/playground.html, + docs/workshop.html, docs/keywords/, and the last failure + allow edits automatically, but ask me before changing visible page copy or headings + + use skills: seo-audit + remember in "docs/seo.memory.md" + + # ── Engine: the repeated cycle ──────────────────────────────────────────────── + each cycle: plan, then act, then observe + + # ── Safety net: back-edge, escape hatch, hard stop ──────────────────────────── + when it fails: reflect on which pages and which tags still fail, then plan again + when blocked: ask a human + a human reviews before stopping + after 8 tries: stop and warn "SEO still failing after 8 passes — narrow look at: to the worst pages" From d3000419932aeb40515e278669935a7692a780ec Mon Sep 17 00:00:00 2001 From: tickets-forge-dev <ticketsforge@gmail.com> Date: Sun, 5 Jul 2026 00:24:43 -0400 Subject: [PATCH 2/9] seo: add Plausible analytics + keyword-content loop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - inject privacy-friendly Plausible analytics tag into all 30 docs pages (keys off data-domain=loopflow.live; records once the account is created) - add docs/tools/check_content.py — content-depth gate for keyword pages (>=220 words, >=2 examples, a pitfalls section, related links) - add seo-content.loop — expands the thin keyword reference pages until the content checker passes and a human approves (quality gate, no padding) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- docs/game.html | 1 + docs/index.html | 1 + docs/keywords/after-n-tries.html | 3 +- docs/keywords/allow.html | 3 +- docs/keywords/also.html | 3 +- docs/keywords/done-when.html | 3 +- docs/keywords/each-cycle.html | 3 +- docs/keywords/flow.html | 3 +- docs/keywords/for-each.html | 3 +- docs/keywords/git.html | 3 +- docs/keywords/goal.html | 3 +- docs/keywords/human-gates.html | 3 +- docs/keywords/index.html | 3 +- docs/keywords/look-at.html | 3 +- docs/keywords/loop.html | 3 +- docs/keywords/models.html | 3 +- docs/keywords/notify.html | 3 +- docs/keywords/pipeline.html | 3 +- docs/keywords/plan-from.html | 3 +- docs/keywords/reflect.html | 3 +- docs/keywords/remember-in.html | 3 +- docs/keywords/run.html | 3 +- docs/keywords/schedule.html | 3 +- docs/keywords/stage.html | 3 +- docs/keywords/target.html | 3 +- docs/keywords/use-method.html | 3 +- docs/keywords/use-skills.html | 3 +- docs/keywords/when.html | 3 +- docs/playground.html | 1 + docs/tools/check_content.py | 57 ++++++++++++++++++++++++++++++++ docs/workshop.html | 1 + seo-content.loop | 33 ++++++++++++++++++ 32 files changed, 146 insertions(+), 26 deletions(-) create mode 100644 docs/tools/check_content.py create mode 100644 seo-content.loop diff --git a/docs/game.html b/docs/game.html index ccfd6f4..58e1eed 100644 --- a/docs/game.html +++ b/docs/game.html @@ -233,6 +233,7 @@ .startbtn:hover{filter:brightness(1.07);} @media(max-width:640px){ .pblock{min-width:0; flex:1 1 44%;} .brand{font-size:21px;} .card.lvl h2{font-size:23px;} } </style> +<script defer data-domain="loopflow.live" src="https://plausible.io/js/script.js"></script> </head> <body> <h1 style="position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0">LoopFlow Lab — learn loop engineering by building loops</h1> diff --git a/docs/index.html b/docs/index.html index 037788d..70b2956 100644 --- a/docs/index.html +++ b/docs/index.html @@ -200,6 +200,7 @@ .heroduo .duo-arrow{transform:rotate(90deg);padding:0} } </style> +<script defer data-domain="loopflow.live" src="https://plausible.io/js/script.js"></script> </head> <body> <svg width="0" height="0" style="position:absolute" aria-hidden="true"><defs> diff --git a/docs/keywords/after-n-tries.html b/docs/keywords/after-n-tries.html index c7aa09a..d00415d 100644 --- a/docs/keywords/after-n-tries.html +++ b/docs/keywords/after-n-tries.html @@ -15,7 +15,8 @@ <script type="application/ld+json">{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"LoopFlow","item":"https://loopflow.live/"},{"@type":"ListItem","position":2,"name":"Keywords","item":"https://loopflow.live/keywords/"},{"@type":"ListItem","position":3,"name":"after N tries (thrash guard)","item":"https://loopflow.live/keywords/after-n-tries.html"}]}</script> <link rel="preconnect" href="https://fonts.googleapis.com"/><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/> <link href="https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400;0,500;0,700;1,400;1,500&family=Ubuntu+Mono:ital,wght@0,400;0,700;1,400&display=swap" rel="stylesheet"/> -<link rel="stylesheet" href="style.css"/></head><body> +<link rel="stylesheet" href="style.css"/><script defer data-domain="loopflow.live" src="https://plausible.io/js/script.js"></script> +</head><body> <svg width="0" height="0" style="position:absolute" aria-hidden="true"><defs> <marker id="dgA" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#5b6678"/></marker> <marker id="dgAr" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#ffb45a"/></marker> diff --git a/docs/keywords/allow.html b/docs/keywords/allow.html index 1d65309..13f792a 100644 --- a/docs/keywords/allow.html +++ b/docs/keywords/allow.html @@ -15,7 +15,8 @@ <script type="application/ld+json">{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"LoopFlow","item":"https://loopflow.live/"},{"@type":"ListItem","position":2,"name":"Keywords","item":"https://loopflow.live/keywords/"},{"@type":"ListItem","position":3,"name":"allow / ask me before","item":"https://loopflow.live/keywords/allow.html"}]}</script> <link rel="preconnect" href="https://fonts.googleapis.com"/><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/> <link href="https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400;0,500;0,700;1,400;1,500&family=Ubuntu+Mono:ital,wght@0,400;0,700;1,400&display=swap" rel="stylesheet"/> -<link rel="stylesheet" href="style.css"/></head><body> +<link rel="stylesheet" href="style.css"/><script defer data-domain="loopflow.live" src="https://plausible.io/js/script.js"></script> +</head><body> <svg width="0" height="0" style="position:absolute" aria-hidden="true"><defs> <marker id="dgA" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#5b6678"/></marker> <marker id="dgAr" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#ffb45a"/></marker> diff --git a/docs/keywords/also.html b/docs/keywords/also.html index 603f9e6..e9e082a 100644 --- a/docs/keywords/also.html +++ b/docs/keywords/also.html @@ -15,7 +15,8 @@ <script type="application/ld+json">{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"LoopFlow","item":"https://loopflow.live/"},{"@type":"ListItem","position":2,"name":"Keywords","item":"https://loopflow.live/keywords/"},{"@type":"ListItem","position":3,"name":"also","item":"https://loopflow.live/keywords/also.html"}]}</script> <link rel="preconnect" href="https://fonts.googleapis.com"/><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/> <link href="https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400;0,500;0,700;1,400;1,500&family=Ubuntu+Mono:ital,wght@0,400;0,700;1,400&display=swap" rel="stylesheet"/> -<link rel="stylesheet" href="style.css"/></head><body> +<link rel="stylesheet" href="style.css"/><script defer data-domain="loopflow.live" src="https://plausible.io/js/script.js"></script> +</head><body> <svg width="0" height="0" style="position:absolute" aria-hidden="true"><defs> <marker id="dgA" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#5b6678"/></marker> <marker id="dgAr" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#ffb45a"/></marker> diff --git a/docs/keywords/done-when.html b/docs/keywords/done-when.html index 8021a39..89018be 100644 --- a/docs/keywords/done-when.html +++ b/docs/keywords/done-when.html @@ -15,7 +15,8 @@ <script type="application/ld+json">{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"LoopFlow","item":"https://loopflow.live/"},{"@type":"ListItem","position":2,"name":"Keywords","item":"https://loopflow.live/keywords/"},{"@type":"ListItem","position":3,"name":"done when","item":"https://loopflow.live/keywords/done-when.html"}]}</script> <link rel="preconnect" href="https://fonts.googleapis.com"/><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/> <link href="https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400;0,500;0,700;1,400;1,500&family=Ubuntu+Mono:ital,wght@0,400;0,700;1,400&display=swap" rel="stylesheet"/> -<link rel="stylesheet" href="style.css"/></head><body> +<link rel="stylesheet" href="style.css"/><script defer data-domain="loopflow.live" src="https://plausible.io/js/script.js"></script> +</head><body> <svg width="0" height="0" style="position:absolute" aria-hidden="true"><defs> <marker id="dgA" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#5b6678"/></marker> <marker id="dgAr" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#ffb45a"/></marker> diff --git a/docs/keywords/each-cycle.html b/docs/keywords/each-cycle.html index e3b1bb1..dcb386a 100644 --- a/docs/keywords/each-cycle.html +++ b/docs/keywords/each-cycle.html @@ -15,7 +15,8 @@ <script type="application/ld+json">{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"LoopFlow","item":"https://loopflow.live/"},{"@type":"ListItem","position":2,"name":"Keywords","item":"https://loopflow.live/keywords/"},{"@type":"ListItem","position":3,"name":"each cycle","item":"https://loopflow.live/keywords/each-cycle.html"}]}</script> <link rel="preconnect" href="https://fonts.googleapis.com"/><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/> <link href="https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400;0,500;0,700;1,400;1,500&family=Ubuntu+Mono:ital,wght@0,400;0,700;1,400&display=swap" rel="stylesheet"/> -<link rel="stylesheet" href="style.css"/></head><body> +<link rel="stylesheet" href="style.css"/><script defer data-domain="loopflow.live" src="https://plausible.io/js/script.js"></script> +</head><body> <svg width="0" height="0" style="position:absolute" aria-hidden="true"><defs> <marker id="dgA" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#5b6678"/></marker> <marker id="dgAr" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#ffb45a"/></marker> diff --git a/docs/keywords/flow.html b/docs/keywords/flow.html index 996133f..23096bc 100644 --- a/docs/keywords/flow.html +++ b/docs/keywords/flow.html @@ -15,7 +15,8 @@ <script type="application/ld+json">{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"LoopFlow","item":"https://loopflow.live/"},{"@type":"ListItem","position":2,"name":"Keywords","item":"https://loopflow.live/keywords/"},{"@type":"ListItem","position":3,"name":"flow","item":"https://loopflow.live/keywords/flow.html"}]}</script> <link rel="preconnect" href="https://fonts.googleapis.com"/><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/> <link href="https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400;0,500;0,700;1,400;1,500&family=Ubuntu+Mono:ital,wght@0,400;0,700;1,400&display=swap" rel="stylesheet"/> -<link rel="stylesheet" href="style.css"/></head><body> +<link rel="stylesheet" href="style.css"/><script defer data-domain="loopflow.live" src="https://plausible.io/js/script.js"></script> +</head><body> <svg width="0" height="0" style="position:absolute" aria-hidden="true"><defs> <marker id="dgA" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#5b6678"/></marker> <marker id="dgAr" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#ffb45a"/></marker> diff --git a/docs/keywords/for-each.html b/docs/keywords/for-each.html index 64ce85c..1895cd1 100644 --- a/docs/keywords/for-each.html +++ b/docs/keywords/for-each.html @@ -15,7 +15,8 @@ <script type="application/ld+json">{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"LoopFlow","item":"https://loopflow.live/"},{"@type":"ListItem","position":2,"name":"Keywords","item":"https://loopflow.live/keywords/"},{"@type":"ListItem","position":3,"name":"for each","item":"https://loopflow.live/keywords/for-each.html"}]}</script> <link rel="preconnect" href="https://fonts.googleapis.com"/><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/> <link href="https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400;0,500;0,700;1,400;1,500&family=Ubuntu+Mono:ital,wght@0,400;0,700;1,400&display=swap" rel="stylesheet"/> -<link rel="stylesheet" href="style.css"/></head><body> +<link rel="stylesheet" href="style.css"/><script defer data-domain="loopflow.live" src="https://plausible.io/js/script.js"></script> +</head><body> <svg width="0" height="0" style="position:absolute" aria-hidden="true"><defs> <marker id="dgA" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#5b6678"/></marker> <marker id="dgAr" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#ffb45a"/></marker> diff --git a/docs/keywords/git.html b/docs/keywords/git.html index 5aba4c9..01cd0fe 100644 --- a/docs/keywords/git.html +++ b/docs/keywords/git.html @@ -15,7 +15,8 @@ <script type="application/ld+json">{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"LoopFlow","item":"https://loopflow.live/"},{"@type":"ListItem","position":2,"name":"Keywords","item":"https://loopflow.live/keywords/"},{"@type":"ListItem","position":3,"name":"git:","item":"https://loopflow.live/keywords/git.html"}]}</script> <link rel="preconnect" href="https://fonts.googleapis.com"/><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/> <link href="https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400;0,500;0,700;1,400;1,500&family=Ubuntu+Mono:ital,wght@0,400;0,700;1,400&display=swap" rel="stylesheet"/> -<link rel="stylesheet" href="style.css"/></head><body> +<link rel="stylesheet" href="style.css"/><script defer data-domain="loopflow.live" src="https://plausible.io/js/script.js"></script> +</head><body> <svg width="0" height="0" style="position:absolute" aria-hidden="true"><defs> <marker id="dgA" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#5b6678"/></marker> <marker id="dgAr" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#ffb45a"/></marker> diff --git a/docs/keywords/goal.html b/docs/keywords/goal.html index 8332226..fecc3fc 100644 --- a/docs/keywords/goal.html +++ b/docs/keywords/goal.html @@ -15,7 +15,8 @@ <script type="application/ld+json">{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"LoopFlow","item":"https://loopflow.live/"},{"@type":"ListItem","position":2,"name":"Keywords","item":"https://loopflow.live/keywords/"},{"@type":"ListItem","position":3,"name":"goal","item":"https://loopflow.live/keywords/goal.html"}]}</script> <link rel="preconnect" href="https://fonts.googleapis.com"/><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/> <link href="https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400;0,500;0,700;1,400;1,500&family=Ubuntu+Mono:ital,wght@0,400;0,700;1,400&display=swap" rel="stylesheet"/> -<link rel="stylesheet" href="style.css"/></head><body> +<link rel="stylesheet" href="style.css"/><script defer data-domain="loopflow.live" src="https://plausible.io/js/script.js"></script> +</head><body> <svg width="0" height="0" style="position:absolute" aria-hidden="true"><defs> <marker id="dgA" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#5b6678"/></marker> <marker id="dgAr" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#ffb45a"/></marker> diff --git a/docs/keywords/human-gates.html b/docs/keywords/human-gates.html index 5d37ad6..b21b1b2 100644 --- a/docs/keywords/human-gates.html +++ b/docs/keywords/human-gates.html @@ -15,7 +15,8 @@ <script type="application/ld+json">{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"LoopFlow","item":"https://loopflow.live/"},{"@type":"ListItem","position":2,"name":"Keywords","item":"https://loopflow.live/keywords/"},{"@type":"ListItem","position":3,"name":"human gates","item":"https://loopflow.live/keywords/human-gates.html"}]}</script> <link rel="preconnect" href="https://fonts.googleapis.com"/><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/> <link href="https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400;0,500;0,700;1,400;1,500&family=Ubuntu+Mono:ital,wght@0,400;0,700;1,400&display=swap" rel="stylesheet"/> -<link rel="stylesheet" href="style.css"/></head><body> +<link rel="stylesheet" href="style.css"/><script defer data-domain="loopflow.live" src="https://plausible.io/js/script.js"></script> +</head><body> <svg width="0" height="0" style="position:absolute" aria-hidden="true"><defs> <marker id="dgA" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#5b6678"/></marker> <marker id="dgAr" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#ffb45a"/></marker> diff --git a/docs/keywords/index.html b/docs/keywords/index.html index ba4e7ac..d2fcff7 100644 --- a/docs/keywords/index.html +++ b/docs/keywords/index.html @@ -15,7 +15,8 @@ <script type="application/ld+json">{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"LoopFlow","item":"https://loopflow.live/"},{"@type":"ListItem","position":2,"name":"Keywords","item":"https://loopflow.live/keywords/"},{"@type":"ListItem","position":3,"name":"Keywords","item":"https://loopflow.live/keywords/index.html"}]}</script> <link rel="preconnect" href="https://fonts.googleapis.com"/><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/> <link href="https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400;0,500;0,700;1,400;1,500&family=Ubuntu+Mono:ital,wght@0,400;0,700;1,400&display=swap" rel="stylesheet"/> -<link rel="stylesheet" href="style.css"/></head><body> +<link rel="stylesheet" href="style.css"/><script defer data-domain="loopflow.live" src="https://plausible.io/js/script.js"></script> +</head><body> <svg width="0" height="0" style="position:absolute" aria-hidden="true"><defs> <marker id="dgA" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#5b6678"/></marker> <marker id="dgAr" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#ffb45a"/></marker> diff --git a/docs/keywords/look-at.html b/docs/keywords/look-at.html index b0cc622..efc310b 100644 --- a/docs/keywords/look-at.html +++ b/docs/keywords/look-at.html @@ -15,7 +15,8 @@ <script type="application/ld+json">{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"LoopFlow","item":"https://loopflow.live/"},{"@type":"ListItem","position":2,"name":"Keywords","item":"https://loopflow.live/keywords/"},{"@type":"ListItem","position":3,"name":"look at","item":"https://loopflow.live/keywords/look-at.html"}]}</script> <link rel="preconnect" href="https://fonts.googleapis.com"/><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/> <link href="https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400;0,500;0,700;1,400;1,500&family=Ubuntu+Mono:ital,wght@0,400;0,700;1,400&display=swap" rel="stylesheet"/> -<link rel="stylesheet" href="style.css"/></head><body> +<link rel="stylesheet" href="style.css"/><script defer data-domain="loopflow.live" src="https://plausible.io/js/script.js"></script> +</head><body> <svg width="0" height="0" style="position:absolute" aria-hidden="true"><defs> <marker id="dgA" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#5b6678"/></marker> <marker id="dgAr" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#ffb45a"/></marker> diff --git a/docs/keywords/loop.html b/docs/keywords/loop.html index 4bb50d7..8811237 100644 --- a/docs/keywords/loop.html +++ b/docs/keywords/loop.html @@ -15,7 +15,8 @@ <script type="application/ld+json">{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"LoopFlow","item":"https://loopflow.live/"},{"@type":"ListItem","position":2,"name":"Keywords","item":"https://loopflow.live/keywords/"},{"@type":"ListItem","position":3,"name":"loop","item":"https://loopflow.live/keywords/loop.html"}]}</script> <link rel="preconnect" href="https://fonts.googleapis.com"/><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/> <link href="https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400;0,500;0,700;1,400;1,500&family=Ubuntu+Mono:ital,wght@0,400;0,700;1,400&display=swap" rel="stylesheet"/> -<link rel="stylesheet" href="style.css"/></head><body> +<link rel="stylesheet" href="style.css"/><script defer data-domain="loopflow.live" src="https://plausible.io/js/script.js"></script> +</head><body> <svg width="0" height="0" style="position:absolute" aria-hidden="true"><defs> <marker id="dgA" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#5b6678"/></marker> <marker id="dgAr" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#ffb45a"/></marker> diff --git a/docs/keywords/models.html b/docs/keywords/models.html index 715b4d6..409fd4a 100644 --- a/docs/keywords/models.html +++ b/docs/keywords/models.html @@ -15,7 +15,8 @@ <script type="application/ld+json">{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"LoopFlow","item":"https://loopflow.live/"},{"@type":"ListItem","position":2,"name":"Keywords","item":"https://loopflow.live/keywords/"},{"@type":"ListItem","position":3,"name":"models:","item":"https://loopflow.live/keywords/models.html"}]}</script> <link rel="preconnect" href="https://fonts.googleapis.com"/><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/> <link href="https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400;0,500;0,700;1,400;1,500&family=Ubuntu+Mono:ital,wght@0,400;0,700;1,400&display=swap" rel="stylesheet"/> -<link rel="stylesheet" href="style.css"/></head><body> +<link rel="stylesheet" href="style.css"/><script defer data-domain="loopflow.live" src="https://plausible.io/js/script.js"></script> +</head><body> <svg width="0" height="0" style="position:absolute" aria-hidden="true"><defs> <marker id="dgA" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#5b6678"/></marker> <marker id="dgAr" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#ffb45a"/></marker> diff --git a/docs/keywords/notify.html b/docs/keywords/notify.html index bf80e46..bfc6a25 100644 --- a/docs/keywords/notify.html +++ b/docs/keywords/notify.html @@ -15,7 +15,8 @@ <script type="application/ld+json">{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"LoopFlow","item":"https://loopflow.live/"},{"@type":"ListItem","position":2,"name":"Keywords","item":"https://loopflow.live/keywords/"},{"@type":"ListItem","position":3,"name":"notify","item":"https://loopflow.live/keywords/notify.html"}]}</script> <link rel="preconnect" href="https://fonts.googleapis.com"/><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/> <link href="https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400;0,500;0,700;1,400;1,500&family=Ubuntu+Mono:ital,wght@0,400;0,700;1,400&display=swap" rel="stylesheet"/> -<link rel="stylesheet" href="style.css"/></head><body> +<link rel="stylesheet" href="style.css"/><script defer data-domain="loopflow.live" src="https://plausible.io/js/script.js"></script> +</head><body> <svg width="0" height="0" style="position:absolute" aria-hidden="true"><defs> <marker id="dgA" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#5b6678"/></marker> <marker id="dgAr" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#ffb45a"/></marker> diff --git a/docs/keywords/pipeline.html b/docs/keywords/pipeline.html index 383abbc..c2dc47b 100644 --- a/docs/keywords/pipeline.html +++ b/docs/keywords/pipeline.html @@ -15,7 +15,8 @@ <script type="application/ld+json">{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"LoopFlow","item":"https://loopflow.live/"},{"@type":"ListItem","position":2,"name":"Keywords","item":"https://loopflow.live/keywords/"},{"@type":"ListItem","position":3,"name":"pipeline","item":"https://loopflow.live/keywords/pipeline.html"}]}</script> <link rel="preconnect" href="https://fonts.googleapis.com"/><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/> <link href="https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400;0,500;0,700;1,400;1,500&family=Ubuntu+Mono:ital,wght@0,400;0,700;1,400&display=swap" rel="stylesheet"/> -<link rel="stylesheet" href="style.css"/></head><body> +<link rel="stylesheet" href="style.css"/><script defer data-domain="loopflow.live" src="https://plausible.io/js/script.js"></script> +</head><body> <svg width="0" height="0" style="position:absolute" aria-hidden="true"><defs> <marker id="dgA" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#5b6678"/></marker> <marker id="dgAr" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#ffb45a"/></marker> diff --git a/docs/keywords/plan-from.html b/docs/keywords/plan-from.html index 76794d3..848bc48 100644 --- a/docs/keywords/plan-from.html +++ b/docs/keywords/plan-from.html @@ -15,7 +15,8 @@ <script type="application/ld+json">{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"LoopFlow","item":"https://loopflow.live/"},{"@type":"ListItem","position":2,"name":"Keywords","item":"https://loopflow.live/keywords/"},{"@type":"ListItem","position":3,"name":"plan from","item":"https://loopflow.live/keywords/plan-from.html"}]}</script> <link rel="preconnect" href="https://fonts.googleapis.com"/><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/> <link href="https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400;0,500;0,700;1,400;1,500&family=Ubuntu+Mono:ital,wght@0,400;0,700;1,400&display=swap" rel="stylesheet"/> -<link rel="stylesheet" href="style.css"/></head><body> +<link rel="stylesheet" href="style.css"/><script defer data-domain="loopflow.live" src="https://plausible.io/js/script.js"></script> +</head><body> <svg width="0" height="0" style="position:absolute" aria-hidden="true"><defs> <marker id="dgA" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#5b6678"/></marker> <marker id="dgAr" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#ffb45a"/></marker> diff --git a/docs/keywords/reflect.html b/docs/keywords/reflect.html index 0f4feb6..fc49e9b 100644 --- a/docs/keywords/reflect.html +++ b/docs/keywords/reflect.html @@ -15,7 +15,8 @@ <script type="application/ld+json">{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"LoopFlow","item":"https://loopflow.live/"},{"@type":"ListItem","position":2,"name":"Keywords","item":"https://loopflow.live/keywords/"},{"@type":"ListItem","position":3,"name":"reflect","item":"https://loopflow.live/keywords/reflect.html"}]}</script> <link rel="preconnect" href="https://fonts.googleapis.com"/><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/> <link href="https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400;0,500;0,700;1,400;1,500&family=Ubuntu+Mono:ital,wght@0,400;0,700;1,400&display=swap" rel="stylesheet"/> -<link rel="stylesheet" href="style.css"/></head><body> +<link rel="stylesheet" href="style.css"/><script defer data-domain="loopflow.live" src="https://plausible.io/js/script.js"></script> +</head><body> <svg width="0" height="0" style="position:absolute" aria-hidden="true"><defs> <marker id="dgA" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#5b6678"/></marker> <marker id="dgAr" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#ffb45a"/></marker> diff --git a/docs/keywords/remember-in.html b/docs/keywords/remember-in.html index 59721b8..63e3b2e 100644 --- a/docs/keywords/remember-in.html +++ b/docs/keywords/remember-in.html @@ -15,7 +15,8 @@ <script type="application/ld+json">{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"LoopFlow","item":"https://loopflow.live/"},{"@type":"ListItem","position":2,"name":"Keywords","item":"https://loopflow.live/keywords/"},{"@type":"ListItem","position":3,"name":"remember in","item":"https://loopflow.live/keywords/remember-in.html"}]}</script> <link rel="preconnect" href="https://fonts.googleapis.com"/><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/> <link href="https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400;0,500;0,700;1,400;1,500&family=Ubuntu+Mono:ital,wght@0,400;0,700;1,400&display=swap" rel="stylesheet"/> -<link rel="stylesheet" href="style.css"/></head><body> +<link rel="stylesheet" href="style.css"/><script defer data-domain="loopflow.live" src="https://plausible.io/js/script.js"></script> +</head><body> <svg width="0" height="0" style="position:absolute" aria-hidden="true"><defs> <marker id="dgA" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#5b6678"/></marker> <marker id="dgAr" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#ffb45a"/></marker> diff --git a/docs/keywords/run.html b/docs/keywords/run.html index fd17fa9..0cb947e 100644 --- a/docs/keywords/run.html +++ b/docs/keywords/run.html @@ -15,7 +15,8 @@ <script type="application/ld+json">{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"LoopFlow","item":"https://loopflow.live/"},{"@type":"ListItem","position":2,"name":"Keywords","item":"https://loopflow.live/keywords/"},{"@type":"ListItem","position":3,"name":"run / then run","item":"https://loopflow.live/keywords/run.html"}]}</script> <link rel="preconnect" href="https://fonts.googleapis.com"/><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/> <link href="https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400;0,500;0,700;1,400;1,500&family=Ubuntu+Mono:ital,wght@0,400;0,700;1,400&display=swap" rel="stylesheet"/> -<link rel="stylesheet" href="style.css"/></head><body> +<link rel="stylesheet" href="style.css"/><script defer data-domain="loopflow.live" src="https://plausible.io/js/script.js"></script> +</head><body> <svg width="0" height="0" style="position:absolute" aria-hidden="true"><defs> <marker id="dgA" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#5b6678"/></marker> <marker id="dgAr" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#ffb45a"/></marker> diff --git a/docs/keywords/schedule.html b/docs/keywords/schedule.html index e249765..793dd59 100644 --- a/docs/keywords/schedule.html +++ b/docs/keywords/schedule.html @@ -15,7 +15,8 @@ <script type="application/ld+json">{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"LoopFlow","item":"https://loopflow.live/"},{"@type":"ListItem","position":2,"name":"Keywords","item":"https://loopflow.live/keywords/"},{"@type":"ListItem","position":3,"name":"schedule","item":"https://loopflow.live/keywords/schedule.html"}]}</script> <link rel="preconnect" href="https://fonts.googleapis.com"/><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/> <link href="https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400;0,500;0,700;1,400;1,500&family=Ubuntu+Mono:ital,wght@0,400;0,700;1,400&display=swap" rel="stylesheet"/> -<link rel="stylesheet" href="style.css"/></head><body> +<link rel="stylesheet" href="style.css"/><script defer data-domain="loopflow.live" src="https://plausible.io/js/script.js"></script> +</head><body> <svg width="0" height="0" style="position:absolute" aria-hidden="true"><defs> <marker id="dgA" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#5b6678"/></marker> <marker id="dgAr" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#ffb45a"/></marker> diff --git a/docs/keywords/stage.html b/docs/keywords/stage.html index 4517884..312f567 100644 --- a/docs/keywords/stage.html +++ b/docs/keywords/stage.html @@ -15,7 +15,8 @@ <script type="application/ld+json">{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"LoopFlow","item":"https://loopflow.live/"},{"@type":"ListItem","position":2,"name":"Keywords","item":"https://loopflow.live/keywords/"},{"@type":"ListItem","position":3,"name":"stage","item":"https://loopflow.live/keywords/stage.html"}]}</script> <link rel="preconnect" href="https://fonts.googleapis.com"/><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/> <link href="https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400;0,500;0,700;1,400;1,500&family=Ubuntu+Mono:ital,wght@0,400;0,700;1,400&display=swap" rel="stylesheet"/> -<link rel="stylesheet" href="style.css"/></head><body> +<link rel="stylesheet" href="style.css"/><script defer data-domain="loopflow.live" src="https://plausible.io/js/script.js"></script> +</head><body> <svg width="0" height="0" style="position:absolute" aria-hidden="true"><defs> <marker id="dgA" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#5b6678"/></marker> <marker id="dgAr" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#ffb45a"/></marker> diff --git a/docs/keywords/target.html b/docs/keywords/target.html index ec9fdc6..6154535 100644 --- a/docs/keywords/target.html +++ b/docs/keywords/target.html @@ -15,7 +15,8 @@ <script type="application/ld+json">{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"LoopFlow","item":"https://loopflow.live/"},{"@type":"ListItem","position":2,"name":"Keywords","item":"https://loopflow.live/keywords/"},{"@type":"ListItem","position":3,"name":"target","item":"https://loopflow.live/keywords/target.html"}]}</script> <link rel="preconnect" href="https://fonts.googleapis.com"/><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/> <link href="https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400;0,500;0,700;1,400;1,500&family=Ubuntu+Mono:ital,wght@0,400;0,700;1,400&display=swap" rel="stylesheet"/> -<link rel="stylesheet" href="style.css"/></head><body> +<link rel="stylesheet" href="style.css"/><script defer data-domain="loopflow.live" src="https://plausible.io/js/script.js"></script> +</head><body> <svg width="0" height="0" style="position:absolute" aria-hidden="true"><defs> <marker id="dgA" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#5b6678"/></marker> <marker id="dgAr" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#ffb45a"/></marker> diff --git a/docs/keywords/use-method.html b/docs/keywords/use-method.html index f017331..7adcc81 100644 --- a/docs/keywords/use-method.html +++ b/docs/keywords/use-method.html @@ -15,7 +15,8 @@ <script type="application/ld+json">{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"LoopFlow","item":"https://loopflow.live/"},{"@type":"ListItem","position":2,"name":"Keywords","item":"https://loopflow.live/keywords/"},{"@type":"ListItem","position":3,"name":"use the <X> method","item":"https://loopflow.live/keywords/use-method.html"}]}</script> <link rel="preconnect" href="https://fonts.googleapis.com"/><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/> <link href="https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400;0,500;0,700;1,400;1,500&family=Ubuntu+Mono:ital,wght@0,400;0,700;1,400&display=swap" rel="stylesheet"/> -<link rel="stylesheet" href="style.css"/></head><body> +<link rel="stylesheet" href="style.css"/><script defer data-domain="loopflow.live" src="https://plausible.io/js/script.js"></script> +</head><body> <svg width="0" height="0" style="position:absolute" aria-hidden="true"><defs> <marker id="dgA" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#5b6678"/></marker> <marker id="dgAr" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#ffb45a"/></marker> diff --git a/docs/keywords/use-skills.html b/docs/keywords/use-skills.html index b50e17f..280da5f 100644 --- a/docs/keywords/use-skills.html +++ b/docs/keywords/use-skills.html @@ -15,7 +15,8 @@ <script type="application/ld+json">{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"LoopFlow","item":"https://loopflow.live/"},{"@type":"ListItem","position":2,"name":"Keywords","item":"https://loopflow.live/keywords/"},{"@type":"ListItem","position":3,"name":"use skills","item":"https://loopflow.live/keywords/use-skills.html"}]}</script> <link rel="preconnect" href="https://fonts.googleapis.com"/><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/> <link href="https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400;0,500;0,700;1,400;1,500&family=Ubuntu+Mono:ital,wght@0,400;0,700;1,400&display=swap" rel="stylesheet"/> -<link rel="stylesheet" href="style.css"/></head><body> +<link rel="stylesheet" href="style.css"/><script defer data-domain="loopflow.live" src="https://plausible.io/js/script.js"></script> +</head><body> <svg width="0" height="0" style="position:absolute" aria-hidden="true"><defs> <marker id="dgA" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#5b6678"/></marker> <marker id="dgAr" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#ffb45a"/></marker> diff --git a/docs/keywords/when.html b/docs/keywords/when.html index 13e46a8..f582a10 100644 --- a/docs/keywords/when.html +++ b/docs/keywords/when.html @@ -15,7 +15,8 @@ <script type="application/ld+json">{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"LoopFlow","item":"https://loopflow.live/"},{"@type":"ListItem","position":2,"name":"Keywords","item":"https://loopflow.live/keywords/"},{"@type":"ListItem","position":3,"name":"when \u2026 (transitions)","item":"https://loopflow.live/keywords/when.html"}]}</script> <link rel="preconnect" href="https://fonts.googleapis.com"/><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/> <link href="https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400;0,500;0,700;1,400;1,500&family=Ubuntu+Mono:ital,wght@0,400;0,700;1,400&display=swap" rel="stylesheet"/> -<link rel="stylesheet" href="style.css"/></head><body> +<link rel="stylesheet" href="style.css"/><script defer data-domain="loopflow.live" src="https://plausible.io/js/script.js"></script> +</head><body> <svg width="0" height="0" style="position:absolute" aria-hidden="true"><defs> <marker id="dgA" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#5b6678"/></marker> <marker id="dgAr" markerWidth="9" markerHeight="9" refX="7.5" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="#ffb45a"/></marker> diff --git a/docs/playground.html b/docs/playground.html index 2c514a4..736a620 100644 --- a/docs/playground.html +++ b/docs/playground.html @@ -59,6 +59,7 @@ .hint{color:var(--muted);font-size:12.5px;margin-top:14px;border-top:1px solid var(--line);padding-top:12px} .hint code{font-family:var(--mono);color:var(--ink)} </style> +<script defer data-domain="loopflow.live" src="https://plausible.io/js/script.js"></script> </head> <body> <header> diff --git a/docs/tools/check_content.py b/docs/tools/check_content.py new file mode 100644 index 0000000..cec3f1a --- /dev/null +++ b/docs/tools/check_content.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python3 +"""Content-depth gate for the loopflow.live keyword reference pages. + +A keyword page is a real reference (not a stub) when its <main> has enough prose, +more than one worked example, a pitfalls/gotchas section, and related links. This +script is the `done when` check for the keyword-content loop: it prints every page +that falls short and exits non-zero, so the loop keeps working until all pass. + +Usage: python3 docs/tools/check_content.py +Exit 0 = every keyword page clears the bar (loop may stop). +Exit 1 = at least one page is still thin (offenders printed). +""" +import glob, os, re, sys + +DOCS = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + +MIN_WORDS = 220 # substantial prose, not a one-liner +MIN_EXAMPLES = 2 # more than a single snippet +PITFALL_RE = re.compile(r"pitfall|common mistake|gotcha|when not|watch out|avoid", re.I) + +def main_html(src): + m = re.search(r"<main>(.*?)</main>", src, re.S) + return m.group(1) if m else src + +def check(path): + src = open(path, encoding="utf-8").read() + body = main_html(src) + words = len(re.sub(r"\s+", " ", re.sub(r"<[^>]+>", " ", body)).split()) + examples = len(re.findall(r"<pre", body)) + headings = " ".join(re.findall(r"<h2[^>]*>(.*?)</h2>", body, re.S)) + has_pitfalls = bool(PITFALL_RE.search(re.sub(r"<[^>]+>", " ", headings))) + has_related = 'class="related"' in body or "Related" in headings + fails = [] + if words < MIN_WORDS: fails.append(f"words {words}<{MIN_WORDS}") + if examples < MIN_EXAMPLES: fails.append(f"examples {examples}<{MIN_EXAMPLES}") + if not has_pitfalls: fails.append("no pitfalls/gotchas section") + if not has_related: fails.append("no Related links") + return fails + +def main(): + pages = sorted(p for p in glob.glob(os.path.join(DOCS, "keywords", "*.html")) + if not p.endswith("index.html")) + offenders = [] + for p in pages: + fails = check(p) + if fails: + offenders.append((os.path.relpath(p, DOCS), fails)) + if offenders: + print(f"{len(offenders)}/{len(pages)} keyword pages below the content bar:\n") + for name, fails in offenders: + print(f" {name}: {', '.join(fails)}") + sys.exit(1) + print(f"All {len(pages)} keyword pages clear the content bar " + f"(>= {MIN_WORDS} words, >= {MIN_EXAMPLES} examples, pitfalls + related).") + +if __name__ == "__main__": + main() diff --git a/docs/workshop.html b/docs/workshop.html index 1a8197b..df85c2d 100644 --- a/docs/workshop.html +++ b/docs/workshop.html @@ -122,6 +122,7 @@ .topbar{flex-wrap:wrap; gap:8px;} } </style> +<script defer data-domain="loopflow.live" src="https://plausible.io/js/script.js"></script> </head> <body> diff --git a/seo-content.loop b/seo-content.loop new file mode 100644 index 0000000..052fd82 --- /dev/null +++ b/seo-content.loop @@ -0,0 +1,33 @@ +# seo-content.loop — turn the thin keyword reference pages into real, rankable docs. +# The biggest SEO lever left: search engines rank depth, and every keyword page is +# currently a stub (median ~150 words, no "common mistakes" section, one example). +# The loop expands them until the content-depth checker passes AND a human signs off +# on quality — the checker stops it going green while thin; the human stops it padding. + +loop "seo: expand keyword reference pages": + # ── Contract ────────────────────────────────────────────────────────────────── + goal: every keyword page under docs/keywords/ is a substantial, genuinely useful + reference — a clear explanation of what the keyword does AND why it matters, + at least two worked examples, a "Common mistakes" section, and related links — + accurate to the real grammar, never padded filler. + + done when "python3 docs/tools/check_content.py" passes + + # ── Boundaries ──────────────────────────────────────────────────────────────── + look at: docs/keywords/, docs/keywords/style.css, and the last failure + knowledge: AGENTS.md, docs/MANUAL.md # the grammar — read-only source of truth; never edit + examples: templates/, examples/ # real .loop patterns to draw accurate examples from + + allow edits automatically, but ask me before changing page structure or navigation + use skills: seo-audit # keep title/description/OG correct as bodies grow + + # ── Engine ──────────────────────────────────────────────────────────────────── + each cycle: plan, then act, then observe # each pass: expand the thinnest pages, re-check + + remember in "docs/keywords-content.memory.md" + + # ── Safety net ──────────────────────────────────────────────────────────────── + when it fails: reflect on which pages and which checks still fail, then plan again + when blocked: ask a human + a human reviews before stopping # quality gate — no word-count padding + after 10 tries: stop and warn "content still thin — expand the worst pages by hand" From 2319032dd90174eb1cda580c8c1abded1e160fa8 Mon Sep 17 00:00:00 2001 From: tickets-forge-dev <ticketsforge@gmail.com> Date: Sun, 5 Jul 2026 00:40:46 -0400 Subject: [PATCH 3/9] seo: target "AI coding loop" query cluster + GEO (FAQ, llms.txt, 404, manifest) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Optimize the homepage to rank for the terms people actually search and to be citable by AI search (Claude/ChatGPT/Perplexity): - rewrite <title> and meta description around "self-correcting AI coding loops" (was "LoopFlow — the tutorial", targeting a zero-volume coined term) - weave "AI coding agents / AI coding workflow / one-shot prompts" into the hero copy (homepage went from 0 -> 7 mentions of the target cluster) - add a visible FAQ section + FAQPage JSON-LD (rank for the queries AND give LLMs quotable Q&A to cite) - strengthen llms.txt with a one-line definition, the synonym cluster, and FAQ - add branded 404.html (noindex) and site.webmanifest + theme-color Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- docs/404.html | 35 +++++++++++++++++++++++++++++++++++ docs/index.html | 32 +++++++++++++++++++++++++++++--- docs/llms.txt | 22 ++++++++++++++++++++++ docs/site.webmanifest | 12 ++++++++++++ 4 files changed, 98 insertions(+), 3 deletions(-) create mode 100644 docs/404.html create mode 100644 docs/site.webmanifest diff --git a/docs/404.html b/docs/404.html new file mode 100644 index 0000000..a6a094c --- /dev/null +++ b/docs/404.html @@ -0,0 +1,35 @@ +<!doctype html> +<html lang="en"> +<head> +<meta charset="utf-8" /> +<meta name="viewport" content="width=device-width, initial-scale=1" /> +<meta name="robots" content="noindex" /> +<link rel="icon" type="image/svg+xml" href="/gyro-icon.svg" /> +<title>Page not found — LoopFlow + + + + + + +
+
done when the page exists → failed
+

That loop didn't converge

+

The page you're after isn't here — maybe it moved, or the link was mistyped. No thrash guard needed; just pick a starting point:

+ +
+ + diff --git a/docs/index.html b/docs/index.html index 70b2956..6085d64 100644 --- a/docs/index.html +++ b/docs/index.html @@ -3,9 +3,11 @@ + + -LoopFlow — the tutorial - +LoopFlow — self-correcting AI coding loops in plain English + @@ -261,7 +263,7 @@

Stop babysitting the agent.

Write the goal once — the loop plans, acts, reflects on red, and stops only when the check is green, at the gates you set.
-

LoopFlow is a small natural-language DSL for loop engineering. A .loop file describes a self-correcting, human-gated coding workflow — its objective, the context it may read, the actions it may take, how it verifies itself, and when it stops. This page teaches the whole language from the first line to full A-to-Z pipelines, every section grounded in a real example you can run.

+

LoopFlow is a small natural-language DSL for loop engineering — a way to run AI coding agents in a checked, self-correcting loop instead of one-shot prompts. A .loop file describes a self-correcting, human-gated AI coding workflow — its objective, the context it may read, the actions it may take, how it verifies itself, and when it stops. This page teaches the whole language from the first line to full A-to-Z pipelines, every section grounded in a real example you can run.

@@ -1123,6 +1125,30 @@

Go deeper

+
+

FAQ — AI coding loops, explained

+

What is an AI coding loop?

+

An AI coding loop is a workflow where an AI coding agent repeatedly plans a change, makes it, and checks its own work against a real test or command — retrying and reflecting on each failure until the check passes, instead of stopping after a single attempt. LoopFlow lets you describe one in plain English in a .loop file and run it.

+

How do I make an AI coding agent self-correct?

+

Give the agent a clear goal and a verifiable definition of done — a test, a shell command, or a review — then have it reflect on every failure and try again, with a thrash guard so it can't loop forever. In LoopFlow those are the goal:, done when, reflect, and after N tries lines.

+

What is loop engineering?

+

Loop engineering is designing the loop an AI agent runs in — its goal, the context it may read, the actions it may take, how it verifies itself, and where a human approves — rather than writing one-shot prompts and hoping. A .loop file is that design, written in plain English.

+

How is LoopFlow different from just prompting an AI agent?

+

A one-shot prompt runs once and stops whether or not it worked. A LoopFlow loop keeps going until a real check passes, reflects on failures to improve the next attempt, gates risky steps for a human, and stops on a thrash guard — so "done" is verified, not assumed.

+

What tools does LoopFlow work with?

+

It runs in Claude Code via the /loopflow skill, or headless with loop-run. A .loop file is plain text, so it works with Claude, Cursor, and Copilot — the loop is the artifact, not the tool.

+
+ + +
LoopFlow · loop engineering · Apache-2.0 · GitHub. The full reference lives in AGENTS.md and docs/MANUAL.md; the IR contract is spec/loop-spec.schema.json. Every example on this page is a real, runnable .loop — most ship verbatim under examples/.
diff --git a/docs/llms.txt b/docs/llms.txt index 34d2ac1..87b8414 100644 --- a/docs/llms.txt +++ b/docs/llms.txt @@ -29,6 +29,28 @@ Key concepts (each has a reference page under /keywords/): - [LoopFlow Lab](https://loopflow.live/game.html): learn loop engineering by playing - [Keyword reference](https://loopflow.live/keywords/): every word in the DSL, one page each +## Also known as +LoopFlow is a way to build **AI coding loops** / **AI agent loops** — a **self-correcting +AI agent** that keeps working until a check passes. If you are looking for how to make an +AI coding agent self-correct, retry on failure, or stop only when tests are green, that is +what a LoopFlow `.loop` file describes. The practice is called **loop engineering**. + +## FAQ +Q: What is an AI coding loop? +A: A workflow where an AI coding agent repeatedly plans, makes a change, and checks its own +work against a real test or command — reflecting on each failure and retrying until the +check passes, instead of stopping after one attempt. LoopFlow describes one in plain English. + +Q: How do I make an AI coding agent self-correct? +A: Give it a goal and a verifiable "done" check (a test, command, or review), reflect on each +failure, and add a thrash guard so it can't loop forever. In LoopFlow: `goal:`, `done when`, +`reflect`, and `after N tries`. + +Q: How is LoopFlow different from a one-shot prompt? +A: A one-shot prompt runs once and stops whether or not it worked. A LoopFlow loop runs until +a real check passes, reflects on failures, gates risky steps for a human, and stops on a +thrash guard — so "done" is verified, not assumed. + ## Run it - In Claude Code: the `/loopflow` skill authors and runs `.loop` files in-session. - Headless: `loop-run run .loop`. diff --git a/docs/site.webmanifest b/docs/site.webmanifest new file mode 100644 index 0000000..dccddd0 --- /dev/null +++ b/docs/site.webmanifest @@ -0,0 +1,12 @@ +{ + "name": "LoopFlow", + "short_name": "LoopFlow", + "description": "An open DSL for self-correcting AI coding loops — describe a checked, human-gated AI coding workflow in plain English and run it until the check is green.", + "start_url": "/", + "display": "standalone", + "background_color": "#0b0d12", + "theme_color": "#0b0d12", + "icons": [ + { "src": "/gyro-icon.svg", "type": "image/svg+xml", "sizes": "any", "purpose": "any" } + ] +} From ffb1118ed5f1f2f8cb429a16c7edbd468a62f97d Mon Sep 17 00:00:00 2001 From: tickets-forge-dev Date: Sun, 5 Jul 2026 00:41:59 -0400 Subject: [PATCH 4/9] seo: tighten homepage meta description under 160 chars Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.html b/docs/index.html index 6085d64..ce02239 100644 --- a/docs/index.html +++ b/docs/index.html @@ -7,7 +7,7 @@ LoopFlow — self-correcting AI coding loops in plain English - + From 62bab69c1c386ff8acc22b7c47dedd383f45d360 Mon Sep 17 00:00:00 2001 From: tickets-forge-dev Date: Sun, 5 Jul 2026 00:45:03 -0400 Subject: [PATCH 5/9] docs(readme): lead with 'self-correcting AI coding loops' for search + GEO Co-Authored-By: Claude Opus 4.8 (1M context) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d54fbdd..543bd0d 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@

LoopFlow

-

An open, natural-language DSL for loop engineering.
Describe a staged, self-correcting, human-gated agent workflow in plain English, press ▶, and it runs on Claude Code.

+

An open, natural-language DSL for self-correcting AI coding loops.
Describe what an AI coding agent should build and how to verify it in plain English, press ▶, and it loops until the check passes — a self-correcting alternative to one-shot prompts, on Claude Code, Cursor, or Copilot.

Stop babysitting the agent. Write the goal once — the loop plans, acts, reflects on red,
and stops only when the check is green, at the gates you set.

From 4881bfbbfe69e1932ad0903a9db77707dd7d0e1b Mon Sep 17 00:00:00 2001 From: tickets-forge-dev Date: Sun, 5 Jul 2026 00:52:50 -0400 Subject: [PATCH 6/9] seo(content): expand all 25 keyword reference pages to real depth MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ran seo-content.loop (parallelized across 5 agents): each keyword page now has substantive prose explaining what the keyword does and why, >=2 worked examples, and a "Common mistakes" section — grounded in AGENTS.md for accuracy. Content depth: median 153 -> 508 words/page (min 72 -> 421). All 25 pages now clear docs/tools/check_content.py. Thin pages don't rank; this is the biggest remaining on-page lever for the keyword reference section. Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/keywords/after-n-tries.html | 15 ++++++++++++++- docs/keywords/allow.html | 15 ++++++++++++++- docs/keywords/also.html | 14 +++++++++++++- docs/keywords/done-when.html | 14 +++++++++++++- docs/keywords/each-cycle.html | 10 +++++++++- docs/keywords/flow.html | 10 +++++++++- docs/keywords/for-each.html | 10 +++++++++- docs/keywords/git.html | 10 +++++++++- docs/keywords/goal.html | 15 +++++++++++++-- docs/keywords/human-gates.html | 16 ++++++++++++++-- docs/keywords/look-at.html | 16 +++++++++++++++- docs/keywords/loop.html | 17 ++++++++++++++++- docs/keywords/models.html | 14 +++++++++++++- docs/keywords/notify.html | 19 ++++++++++++++++++- docs/keywords/pipeline.html | 22 +++++++++++++++++++++- docs/keywords/plan-from.html | 9 +++++++++ docs/keywords/reflect.html | 14 ++++++++++++++ docs/keywords/remember-in.html | 9 +++++++++ docs/keywords/run.html | 8 ++++++++ docs/keywords/schedule.html | 19 ++++++++++++++++++- docs/keywords/stage.html | 26 +++++++++++++++++++++++++- docs/keywords/target.html | 24 ++++++++++++++++++++++-- docs/keywords/use-method.html | 22 ++++++++++++++++++++-- docs/keywords/use-skills.html | 21 ++++++++++++++++++++- docs/keywords/when.html | 11 ++++++++++- 25 files changed, 355 insertions(+), 25 deletions(-) diff --git a/docs/keywords/after-n-tries.html b/docs/keywords/after-n-tries.html index d00415d..283813d 100644 --- a/docs/keywords/after-n-tries.html +++ b/docs/keywords/after-n-tries.html @@ -37,9 +37,15 @@

after N tries (thrash guard)

Syntax

after N tries: stop and warn "<message>"

What it does

-

The thrash guard. Because attempts outranks fail, it always wins once the threshold is crossed — so a self-correcting loop warns and stops instead of grinding to the absolute hard cap of 25. Put one on every loop that reflects.

+

The thrash guard — the floor that keeps a self-correcting loop from grinding forever. A loop with a reflect back-edge will retry on every failure; without a ceiling it would loop until it hits the engine's absolute hard cap of 25 attempts, burning tokens on a problem it may never solve unaided. after N tries sets your own, lower limit: once the loop has made N full attempts without meeting the goal, it stops and surfaces the message so a human knows exactly which loop got stuck and why.

+

Reach for it on any loop that reflects. Because attempts is checked before fail in the transition order (see How it runs), the guard always wins once the threshold is crossed — the loop can't sneak in one more reflect-and-retry past the limit. The right N is a budget decision: a cheap, fast done when check can afford 8–10 tries; an expensive one should stop at 3–4. The warning message is your handoff note — write it for the human who reads it, naming the likely cause so they can pick up where the loop left off.

Example

after 6 tries: stop and warn "thrashing — needs a human look"
the thrash guard +
loop "fix the flaky auth test":
+  goal: the login suite is green and stays green
+  done when "pnpm test auth" passes
+  when it fails: reflect on which assertion broke, then plan again
+  after 4 tries: stop and warn "auth test still red — likely a race in the token refresh"
the last line of the loop is its hard stop

How it runs

AFTER EACH OBSERVE — FIRST MATCH WINS @@ -53,6 +59,13 @@

How it runs

4it fails? reflect, then plan again
The order is the engine's, not yours: attempts is checked before fail, so the thrash guard always wins once you hit the limit.
+

Common mistakes

+
    +
  • A reflect back-edge with no guard. A loop that says when it fails: reflect but has no after N tries line will run to the hard cap of 25 before it stops. Never emit a back-edge without a try ceiling — it should be the last line of the loop.
  • +
  • Setting N without pricing the cycle. Each try re-runs plan, act, and the done when check. A slow or costly check with a high N is a big bill for no result. Match the ceiling to the cost: expensive check → low N.
  • +
  • An empty or generic message. stop and warn "failed" tells the human nothing. Name the loop's likely blocker so they can resume from the diagnosis, not from scratch.
  • +
  • Confusing tries with the flake guard. after N tries caps attempts; passes N times in a predicate re-runs the same check to catch a lucky green. They solve different problems — you often want both.
  • +

Related

LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
diff --git a/docs/keywords/allow.html b/docs/keywords/allow.html index 13f792a..1e1a1f3 100644 --- a/docs/keywords/allow.html +++ b/docs/keywords/allow.html @@ -37,10 +37,23 @@

allow / ask me before

Syntax

allow edits automatically, but ask me before migrations or pushes

What it does

-

Splits actions into auto and confirm classes. The canonical classes are edit, migrate, push, deploy, delete. allow … automatically grants without asking; ask me before … pauses once per run and remembers your answer.

+

The action policy — it splits what the loop may do into an auto class it performs without asking and a confirm class that pauses for you first. The canonical classes are edit, migrate, push, deploy, delete. allow … automatically grants a class outright; ask me before … makes the loop stop and wait for a yes/no before it takes that action, then remembers your answer for the rest of the run.

+

This is how you get an unattended loop that is still safe on the irreversible parts. The whole point of a self-correcting loop is that it iterates on its own — but iterating freely over a schema migration, a force-push, or a production deploy is how a green run leaves real damage behind. The policy line lets you say "edit source all you like, but stop at the blast radius": routine work stays fast, risky work stays gated. Reach for it whenever a loop can touch anything you'd want a human to sign off on. It pairs with a human approves before …, which is a harder, per-stage gate for the truly one-way doors; ask me before … is the lighter, run-scoped control for everyday risk. When no policy is given, the loop follows the git strategy's defaults — edits allowed, no push.

Example

allow edits automatically, but ask me before migrations or pushes
per-class policy +
loop "tidy the invoices module":
+  goal: invoices code is clean and the suite is green
+  done when "pnpm test invoices" passes
+  look at: src/invoices/, and the last failure
+  allow edits automatically, but ask me before deletes or migrations
gate only the irreversible actions +

Common mistakes

+
    +
  • Gating nothing on an unattended run. allow edits automatically with no ask me before … lets the loop migrate, delete, and push on its own. On anything irreversible, always name a confirm class.
  • +
  • Using ask me before for a hard stop. It pauses once and remembers your answer for the run — fine for everyday risk, but for a true one-way door (charging a card, a prod deploy) use a human approves before …, a per-stage gate that blocks every time.
  • +
  • Expecting it to override git safety. The policy can't authorize a push to main/master — that's blocked unconditionally regardless of what you allow. Set the branch strategy in a git: block, not here.
  • +
  • Inventing action classes. Stick to the canonical classes — edit, migrate, push, deploy, delete. A made-up class may not map to anything the runner recognizes.
  • +

Related

LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
diff --git a/docs/keywords/also.html b/docs/keywords/also.html index e9e082a..7594738 100644 --- a/docs/keywords/also.html +++ b/docs/keywords/also.html @@ -37,10 +37,22 @@

also

Syntax

also: <pass>, <pass>

What it does

-

Lightweight passes that run only after the goal is met, in order — and are skipped if the loop failed. Use it for chores (polish, security, docs). If a pass needs its own pass/fail check, promote it to a real stage instead.

+

Lists finishing passes that run once, in order, only after the goal is met — and are skipped entirely if the loop failed. Think of them as the chores you want done on a green result but don't want cluttering the core cycle: polish the code, run a security scan, update the docs, tidy imports. They run after the done when check has already passed, so they can't be what makes the loop go green — the goal is the goal, and also is the after-work.

+

Reach for it when a task has a hard, verifiable core plus a few nice-to-haves that don't each deserve their own pass/fail gate. Keeping them out of done when matters: if you fold "and the docs are updated" into the predicate, a docs miss keeps the whole loop red and burns retries on the wrong thing. As an also pass it runs best-effort on success instead. The flip side is the rule of thumb: if a pass needs its own verification — its own test or scan that must pass — it isn't a finishing pass, it's a real stage. Promote it so it gets a proper done when and back-edge. Use also only for work that's fine to run once, unchecked, at the end.

Example

also: polish the code, run a security check, update the docs
finishing passes +
loop "add the CSV export endpoint":
+  goal: GET /reports.csv streams the report as CSV
+  done when "pnpm test reports" passes
+  each cycle: plan, then act, then observe
+  also: update the API docs, add a changelog entry
chores that run once, on success +

Common mistakes

+
    +
  • Putting verifiable work in also. A finishing pass runs once and isn't checked. If the pass must be proven correct, it belongs in done when or its own stage — not here.
  • +
  • Expecting it to run on failure. also passes are skipped when the loop never met its goal. Don't stash cleanup you need on every exit here — use a hooks: on stop line for that.
  • +
  • Overloading it with core work. "also: build the feature" isn't a finishing pass — the feature is the goal. Keep also for genuine after-work (polish, docs, scans), and let the goal carry the real deliverable.
  • +

Related

LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
diff --git a/docs/keywords/done-when.html b/docs/keywords/done-when.html index 89018be..c8a7508 100644 --- a/docs/keywords/done-when.html +++ b/docs/keywords/done-when.html @@ -37,13 +37,25 @@

done when

Syntax

done when <predicate>

What it does

-

The spine of "you can't fake done" — a real command run each cycle. Four forms: a test passes, a command passes, a scan finds nothing (exit 0 and empty output), or a human confirms.

+

The spine of "you can't fake done" — the predicate the loop actually runs each cycle to decide whether it's finished. It's the difference between a loop and an open-ended prompt: the agent doesn't get to declare success, it has to pass a check. The command runs in your shell with your privileges, like an npm script, so it must be a real, runnable command — a paraphrased or aspirational check is a loop that can never go green.

+

There are four forms. A test passes (a named test or suite). A command passes (exit code 0). A scan finds nothing — which means both exit 0 and empty output, so a lingering match keeps the loop red. Or a human confirms a plain-language condition, for the things only an eye can judge. Two modifiers sharpen a check: passes N times re-runs it to smoke out a lucky green (a flake guard), and a skill predicate (the skill "…" approves) hands judgment to a rubric or LM judge for the non-deterministic parts. You can list as many done when lines as you need — all of them must pass, a conjunction — which is how you combine a deterministic test with an eval that judges how the work was done. Write this line first, before any behavior: if you can't state the check, you don't yet understand the goal.

Example

done when the test "billing.spec.ts::apostrophe" passes
 done when "pnpm test" passes
 done when "semgrep --severity=high" finds nothing
 done when a human confirms "the UI looks right"
the four forms +
# combine a deterministic test with a trajectory eval — both must pass
+done when "pnpm test cart" passes 3 times
+done when the skill "code-review" approves on the trajectory
+  the bar: didn't weaken a test to go green; no writes outside src/cart/
test + eval, and a flake guard +

Common mistakes

+
    +
  • A paraphrased or fictional command. The predicate runs verbatim in your shell. If the command doesn't exist or the test name is wrong, the loop can never go green. Run the check by hand once before you ship the loop.
  • +
  • Confusing passes with finds nothing. passes only wants exit 0; a scan that exits 0 but prints matches would falsely pass. Use finds nothing for scanners — it requires exit 0 and empty output.
  • +
  • Only a human check on an unattended loop. a human confirms … blocks until someone answers — fine in-session, a dead stop for a headless run. Pair it with a machine check, or make the deterministic form the gate.
  • +
  • A slow check with no flake guard on flaky suites. A costly predicate re-run every cycle is expensive; a flaky one can pass by luck. Add passes N times where a green can happen by chance.
  • +

Related

LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
diff --git a/docs/keywords/each-cycle.html b/docs/keywords/each-cycle.html index dcb386a..91e4e27 100644 --- a/docs/keywords/each-cycle.html +++ b/docs/keywords/each-cycle.html @@ -37,7 +37,8 @@

each cycle

Syntax

each cycle: plan, then act, then observe

What it does

-

Lists the steps a cycle repeats — any subset of plan, act, observe, in order. This is the default, so you can omit it. plan runs read-only; act makes the change; observe runs the done-when check.

+

Defines the repeated unit of work — the steps the loop runs, in order, on every pass until the goal is met. It's any subset of three verbs: plan reads context and decides the next move read-only; act makes the actual change; observe runs the done when check to see if the loop is finished. The full plan, then act, then observe is the default self-correcting unit, so you can omit the line entirely and get it for free.

+

You'd write the line to trim the cycle when a phase is wasted effort. A mechanical, well-scoped change often doesn't need a planning step — act, then observe just does it and checks, saving a model call per cycle. On the other end, an ambiguous task benefits from keeping plan so the agent reasons before it writes. The order is fixed to the verbs you list; you don't invent new steps. Two related places also set it: a config-tier each cycle: at the top of the file sets the default for every loop below, and a loop's own line overrides that default just for itself. Whatever the shape, the observe step is what closes the loop — it runs the predicate that decides pass (stop) or fail (reflect into the next plan), so a cycle without a way to observe can never end on its own.

Example

each cycle: plan, then act, then observe   # full self-correcting unit
 each cycle: act, then observe              # skip planning — just do + check
two shapes @@ -54,6 +55,13 @@

How it runs

when it fails → reflect, then plan again
Every cycle runs plan → act → observe; the done when check decides — pass → stop, fail → reflect into the next plan.
+

Common mistakes

+
    +
  • Dropping observe. Without it the loop never runs its done when check, so it can't tell it's finished. Every cycle needs a way to observe or it runs blind to the hard cap.
  • +
  • Cutting plan on an ambiguous task. act, then observe saves a call, but on fuzzy work the agent writes before it reasons and thrashes. Keep planning unless the change is genuinely mechanical.
  • +
  • Inventing steps. The vocabulary is exactly plan, act, observe. A verb like "review" or "test" isn't a cycle step — put verification in done when and after-work in also.
  • +
  • Forgetting the config-tier default wins by scope. A file-level each cycle: sets the default; a loop's own line overrides it just for that loop. If a stage isn't cycling as you expect, check which level set it.
  • +

Related

LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
diff --git a/docs/keywords/flow.html b/docs/keywords/flow.html index 23096bc..0e428ff 100644 --- a/docs/keywords/flow.html +++ b/docs/keywords/flow.html @@ -39,7 +39,8 @@

Syntax

run "a.loop" then run "b.loop"

What it does

-

A pipeline lives in one file; a flow chains separate .loop files, run in order — so a big effort is many small reusable files. Fail-fast; a short text summary carries forward.

+

A pipeline lives in one file; a flow chains separate .loop files, run in order — so a big effort becomes many small, reusable files instead of one monolith. Each step runs the whole file (its full plan→act→observe cycle), and its short text summary carries forward as context for the next step. The chain is fail-fast: a step that ends unsatisfied halts the rest.

+

Reach for a flow when the stages are genuinely independent deliverables you'd want to run, resume, or reuse on their own — build.loop, test.loop, deploy.loop — rather than tightly-coupled stories that only make sense together (that's a pipeline). The unit of reuse is the file: the same test.loop can appear in several flows. Use then run for a step that should receive the previous step's summary automatically, or with the result of <name> to pull a specific named step's output instead of the auto-carried one. Attach a human approves first to any step that must not run unattended — a deploy, a migration — and the flow blocks there until approved. Because a flow is just an ordering of files, it stays flat and readable even as the overall effort grows.

Example

flow "ship":
   run "build.loop"
@@ -55,6 +56,13 @@ 

How it runs

👤 approves first📄 deploy.loopall loops inside runs in order · ✗ a file that isn't satisfied halts the rest
A flow chains separate .loop files; after each, a short text summary carries into the next as context.
+

Common mistakes

+
    +
  • Using a flow where a pipeline belongs. If the steps are tightly-coupled stories in one epic, they belong in a single pipeline as stages. A flow is for separate, independently-runnable .loop files.
  • +
  • Assuming files share state. Only a short text summary crosses between steps — not the full transcript, working memory, or variables. If a later step needs a specific earlier output, name that step and use with the result of <name> rather than hoping it survived the auto-carry.
  • +
  • Forgetting fail-fast. A step that ends unsatisfied stops the whole chain; later steps never run. Put the cheap, likely-to-fail checks early so you don't pay for expensive steps before a gate that was going to block anyway.
  • +
  • Wrong relative paths. Each run "<file>" path is resolved relative to the flow file. A path that's right from your shell but wrong from the flow file's directory makes the step unrunnable.
  • +

Related

LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
diff --git a/docs/keywords/for-each.html b/docs/keywords/for-each.html index 1895cd1..4f73a60 100644 --- a/docs/keywords/for-each.html +++ b/docs/keywords/for-each.html @@ -38,7 +38,8 @@

Syntax

for each <var> in "<file>":
   run "<template.loop>"

What it does

-

Dynamic fan-out: read a plan file (discovered at planning time) and run a template loop once per item — each item's text becomes that run's context. If an item's checklist fails, the flow pauses and asks: continue or stop?

+

Dynamic fan-out inside a flow: read a plan file and run a single template loop once per item — each item's text becomes that run's context (what to build). The source is a .yaml file (a list, or a single-key list like items:) or a .md file (which splits on each ## section). If an item's own checklist fails, the flow pauses and asks: continue with the next item, or stop?

+

Reach for for each when you have a backlog of same-shaped work — a dozen endpoints to scaffold, a list of stories to deliver, a set of files to migrate — where the steps are identical but the subject differs each time. Instead of writing one stage per item by hand, you write the template once and let a planning step discover the list at run time. That is the key difference from a fixed pipeline: the number and content of items are not known when you author the flow; they are read from the plan file when the flow runs, so the same flow adapts as the backlog grows or shrinks. It is method-neutral — the plan file can be any checklist, not only a BMAD backlog — and the per-item pause on failure keeps a single bad item from silently poisoning the whole batch.

Examples

flow "deliver":
   for each item in "plan.yaml":
@@ -60,6 +61,13 @@ 

How it runs

▶ item-template.loop same template, once per item — if one fails, it pauses and asks: continue or stop?
for each is dynamic fan-out: a planning step discovers the items, then the same template runs once per item.
+

Common mistakes

+
    +
  • Using it outside a flow. for each only lives inside a flow. It is not a general loop construct — a single self-correcting loop uses loop, and a fixed sequence uses pipeline.
  • +
  • An unsupported source file. The list must come from a .yaml file (a list or a single-key items: list) or a .md file split on ## headings. Point it at anything else and there are no items to fan out over.
  • +
  • A template with no per-item check. The pause-on-failure only triggers if the template's own done when can fail. A template with no real check will "succeed" on every item, including the broken ones — give the template a verifiable predicate.
  • +
  • Expecting items to share context. Each item runs the template fresh with only that item's text as context. Items don't see each other's results; if item 3 depends on item 1's output, model that dependency explicitly rather than assuming order carries state.
  • +

Related

LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
diff --git a/docs/keywords/git.html b/docs/keywords/git.html index 01cd0fe..51f9029 100644 --- a/docs/keywords/git.html +++ b/docs/keywords/git.html @@ -40,7 +40,8 @@

Syntax

commit when the goal is met open a pull request

What it does

-

By default — no block — LoopFlow works on a branch, commits when the goal is met, and never pushes to main/master. A git: block refines: work in place / on a branch / in a worktree; commit when the goal is met / each cycle / each story / never; push when done; open a pull request. Cascades file → loop.

+

A git: block sets the version-control strategy — how the loop branches, commits, and pushes. With no block at all, LoopFlow works on a branch, commits once when the goal is met, and does not push. A block refines any of three axes: where the work happens (work in place / on a branch / on a branch "name" / in a worktree); when it commits (commit when the goal is met / each cycle / each story / never); and whether it leaves the machine (push when done, then optionally open a pull request).

+

Reach for an explicit block when the default cadence doesn't fit the job. commit each cycle gives you a granular history (and easy rollback) while a loop iterates; commit each story lands one commit per stage of a pipeline; work in a worktree isolates a risky run from your working tree entirely. The block sits at one of two levels: at the config tier (top of the file, before any definition) it applies to every loop in the file; inside a loop body it refines just that loop. The cascade is lowest-wins — built-in default, then a repo-wide loop.config, then the file's block, then a per-loop block — so you set the broad policy once and override only where needed. One rule sits outside the cascade and cannot be overridden by any block: never push to main or master. A push when done aimed at a protected branch is an error that surfaces before the loop runs, not a surprise after.

Example

git:
   work on a branch
@@ -58,6 +59,13 @@ 

How it runs

🔒 neverpush to main always on —can't beoverridden
Three layers, each refining the one above. The protected-branch rule sits outside all of them: pushing to main/master is always refused.
+

Common mistakes

+
    +
  • Expecting to push to main. push when done on main/master is refused unconditionally — no block can override it — and it fails up front, before the loop starts. Push a feature branch and open a pull request instead.
  • +
  • work in place + push when done on a protected branch. Same unconditional error: editing the current branch as-is and then pushing it, when that branch is protected, is caught before the run.
  • +
  • Misreading the cascade. Lowest wins — a per-loop block overrides the file block, which overrides loop.config. If a loop isn't committing the way you expect, check for a narrower block quietly overriding the broader one.
  • +
  • commit each cycle on a long loop. Great for granular history and rollback, but a thrashing loop can produce a noisy pile of commits. If that's not what you want, keep the default commit when the goal is met for a single clean commit.
  • +

Related

LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
diff --git a/docs/keywords/goal.html b/docs/keywords/goal.html index fecc3fc..6c7fc6a 100644 --- a/docs/keywords/goal.html +++ b/docs/keywords/goal.html @@ -37,10 +37,21 @@

goal

Syntax

goal: <text>

What it does

-

The objective, stated plainly. Required in every loop. It frames the work; done when is what actually decides success.

+

The objective, stated plainly — one line of natural language that names the outcome the loop is chasing. It is required in every loop: a loop without a goal does not parse, and each stage of a pipeline carries its own. The goal frames the work — it is what the planner reads first and what every cycle steers toward — but it does not decide success. That job belongs to done when, the machine-checkable predicate underneath it.

+

Reach for a sharp goal because it is the loop's compass, not its finish line. Write it as an outcome ("settings save when the name has an apostrophe"), not a task list ("edit the form and the API"), so the agent is free to find the smallest correct change instead of following your guessed steps. The authoring order puts goal first and done when immediately under it for a reason: if you cannot phrase a check for the goal, the goal is not yet understood — that is the signal to sharpen it before writing another line. A goal broad enough to need three tests is really three stages; a goal you cannot verify at all is a prompt, not a loop.

Example

goal: settings save when the company name has an apostrophe
a goal line - +

Paired with its check

+
loop "fix billing apostrophe bug":
+  goal: settings save when the company name has an apostrophe
+  done when the test "billing.spec.ts::apostrophe" passes
goal on top, the check right under it +

Common mistakes

+
    +
  • Writing a task, not an outcome. "Refactor the settings form" tells the agent what to touch, not what "done" looks like — it will thrash. State the result you want and let the loop find the change.
  • +
  • A goal you can't check. If no done when predicate can express the goal, it is too vague or too big. Sharpen it, or split it into stages that each have a check — a goal without a verifiable check is a normal prompt, not a loop.
  • +
  • Cramming an epic into one goal line. A goal that needs several unrelated tests to confirm is really a pipeline of stages. Keep one goal to one checkable outcome.
  • +
  • Leaning on the goal to gate risk. The goal frames intent; it does not stop the agent from doing something dangerous. Put risky work behind ask me before … or a human gate, not in prose the planner may reinterpret.
  • +

Related

LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
diff --git a/docs/keywords/human-gates.html b/docs/keywords/human-gates.html index b21b1b2..b089343 100644 --- a/docs/keywords/human-gates.html +++ b/docs/keywords/human-gates.html @@ -39,13 +39,25 @@

Syntax

a human reviews before stopping a human approves before <X>

What it does

-

Five places a person enters the loop: approve the plan before any acting; review the result before the loop may stop; a hard blocking gate before a stage (deploys, provisioning); when blocked: ask a human; and the per-run confirm from the action policy (ask me before …).

+

Human gates are where a person enters an otherwise self-driving loop. There are five of them, each at a different moment: approve the plan before any acting (a human approves the plan first); review the result before the loop may stop (a human reviews before stopping); a hard blocking gate before a specific action or stage such as a deploy or a card charge (a human approves before <X>); the escape hatch when the loop gets stuck (when blocked: ask a human); and the per-run confirm that comes from the action policy (allow edits automatically, but ask me before …).

+

Reach for a gate wherever a mistake is expensive or irreversible — payments, migrations, deploys, provisioning, anything you cannot cheaply undo. A loop is fast precisely because it does not stop to ask; a gate deliberately trades that speed for a checkpoint, so spend gates where the blast radius justifies the pause and nowhere else. The plan gate catches a wrong approach before any tokens are spent acting on it; the review gate catches a green-but-wrong result before it ships; the blocking gate is the one that stops a genuinely dangerous single step. Gates compose with the automatic verification, not instead of it — done when still decides correctness, and the human judges the parts a predicate can't.

Example

a human approves the plan first        # before any work
 a human reviews before stopping        # judge the result
 a human approves before provisioning   # blocking stage gate
 when blocked: ask a human              # unblock when stuck
the gate forms - +

A gate on a risky stage

+
stage "story: checkout submit":
+  goal: order submits and payment is captured
+  a human approves before charging the card   # blocks until approved
+  done when "pnpm test checkout" passes
a blocking gate before an irreversible action +

Common mistakes

+
    +
  • Gating everything. A gate on every cycle turns the loop back into manual work and defeats the point. Reserve gates for irreversible or high-cost actions; let the fast, checkable work run unattended.
  • +
  • Confusing the gate with the check. a human reviews before stopping judges the result, but it does not replace done when — the loop still needs a machine check to know it is even a candidate to stop. Keep both.
  • +
  • A blocking gate with no async posture. a human approves before <X> halts the run until someone answers. On an unattended or headless run that means it hangs — pair irreversible gates with mode: orchestrator (opens a PR) so the wait happens out of band.
  • +
  • Relying on the goal instead of a gate. Prose in the goal like "be careful with payments" is not enforced. Only an explicit gate or ask me before … actually blocks the agent.
  • +

Related

LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
diff --git a/docs/keywords/look-at.html b/docs/keywords/look-at.html index efc310b..6da51df 100644 --- a/docs/keywords/look-at.html +++ b/docs/keywords/look-at.html @@ -37,10 +37,24 @@

look at

Syntax

look at: <files>, and the last failure

What it does

-

Points the agent at the context that matters before acting. Items are exact paths or plain-language descriptions it resolves to files. The phrase and the last failure feeds the previous failure's output back in.

+

Points the agent at the context that matters before it plans or acts. Items are exact paths or plain-language descriptions the agent resolves to real files — billing/form.tsx is a path; the settings API is a description it looks up first. This is the scope line, and scope is what keeps a loop honest: without it an agent tends to write greenfield code or wander into files it shouldn't touch. With a tight look at: it follows the existing architecture and makes the smallest change that clears the done when check.

+

Why it matters: the list you give here is also the list the agent doesn't read. Fewer, more relevant files mean a sharper plan, cheaper cycles, and less thrash. When a loop starts flailing, the first fix is almost always to narrow look at:, not widen it. The trailing phrase and the last failure is what closes the self-correcting circuit — it feeds the previous cycle's failing output back into the next plan, so reflect actually reaches the agent. Drop it and the loop reads the same files every cycle with no memory of what just broke.

+

look at: has friendly shorthands that parse identically — in:, look in:, files:, and context:. Use whichever reads best; they all desugar to the same scope line.

Example

look at: billing/form.tsx, the settings API, and the last failure
scoped context +

Example — description plus the back-edge

+
loop "fix the cart total rounding":
+  goal: cart totals round to two decimals everywhere
+  done when "pnpm test cart" passes
+  look at: src/cart/, the tax helper, and the last failure
+  when it fails: reflect, then plan again
path + description + reflect +

Common mistakes

+
    +
  • Forgetting and the last failure. Without it the diagnosis from reflect never reaches the next plan, so a self-correcting loop loses its memory and repeats the same broken attempt. Always end the list with it when the loop has a when it fails back-edge.
  • +
  • Listing too many files. A sprawling look at: dilutes the plan and burns tokens. When a loop thrashes, tighten scope to the few files that matter — the fix is to narrow, not widen.
  • +
  • Treating it as an edit whitelist. look at: is read scope, not a permission boundary. What the agent is allowed to change is governed by allow … ask me before …; use that for power, not this line.
  • +

Related

LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
diff --git a/docs/keywords/loop.html b/docs/keywords/loop.html index 8811237..2b7bfe8 100644 --- a/docs/keywords/loop.html +++ b/docs/keywords/loop.html @@ -37,7 +37,8 @@

loop

Syntax

loop "<name>":

What it does

-

The core construct: a goal, a way to verify it (done when), the repeated steps, and what to do on failure. The smallest real loop is just a goal and a done-when.

+

The core construct of LoopFlow: a goal, a way to verify it (done when), the repeated steps (each cycle), and what to do on failure. Every cycle runs plan → act → observe, then the done when predicate decides — pass and the loop stops, fail and it reflects the failure into the next plan. That back-edge is the whole point: a loop is a normal agent that checks its own work and tries again until a verifiable definition of done is met.

+

Reach for a loop when the task is repeatable and "done" is checkable — a bug with a failing test, a refactor gated by a command, a migration with a verification step. If there's no way to verify completion, there's no loop; the done when line is written first, before any behavior, because a check that can never pass loops forever. The smallest real loop is just a goal and a done when; everything else — look at: for scope, human gates for risky work, after N tries for a thrash guard — is added as the job demands. Blocks start at column 0 and their body is indented two spaces.

Example

loop "fix the failing checkout tax test":
   goal: the tax line is correct at checkout
@@ -57,6 +58,20 @@ 

How it runs

when it fails → reflect, then plan again
Every cycle runs plan → act → observe; the done when check decides — pass → stop, fail → reflect into the next plan.
+

Example — with a thrash guard

+
loop "fix billing apostrophe bug":
+  goal: settings save when the company name has an apostrophe
+  done when the test "billing.spec.ts::apostrophe" passes
+  look at: billing/form.tsx, api/settings.ts, and the last failure
+  when it fails: reflect, then plan again
+  after 6 tries: stop and warn "thrashing"
the finish line first, the safety net last +

Common mistakes

+
    +
  • A loop with no done when. A loop requires a goal, but a goal without a verifiable check is just a prompt — the loop can never confirm it's finished. Write the done when line before any behavior.
  • +
  • A back-edge with no ceiling. Never emit when it fails: reflect without an after N tries: stop and warn. A reflect edge with no floor can loop forever on a check that never goes green.
  • +
  • Paraphrasing the predicate command. The shell command in done when runs verbatim in your shell — quote it exactly. A misremembered command is a loop that can never pass.
  • +
  • Indentation drift. loop sits at column 0; its body is indented two spaces. Mixed indentation is the most common parse error — run loop-run show file.loop to check the shape.
  • +

Related

LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
diff --git a/docs/keywords/models.html b/docs/keywords/models.html index 409fd4a..48db527 100644 --- a/docs/keywords/models.html +++ b/docs/keywords/models.html @@ -37,7 +37,8 @@

models:

Syntax

models: fast <model>, strong <model>

What it does

-

Name two tiers and the engine auto-assigns plan / reflect / also → fast and act → strong (observe is a shell check, no model). Override a phase or use all; cascades file → loop → stage; --model overrides everything. A stack of cheap calls plus one strong act — and an end-of-run per-tier cost summary so the spend is measurable.

+

Name two tiers — a fast model and a strong one — and the engine auto-assigns them by phase: plan / reflect / also → fast and act → strong. observe is a shell check with no model at all, so it never costs a token. The reasoning is economic: most cycles are cheap thinking (planning the change, digesting a failure, running finishing passes) and only the act phase writes code that has to be right. Paying strong-model rates for every plan and reflect is waste; tiering routes the expensive model to the one phase that needs it and lets a cheap model carry the rest.

+

You can override any single phase or set them all at once — models: act fast pulls act down to the cheap tier, models: all strong puts everything on the strong one. Like other config-tier lines it cascades file → loop → stage (nearest wins), and a command-line --model flag overrides everything. At the end of a run the engine prints a per-tier cost summary, so the spend is measurable rather than a guess. Pair it with an observe: cost cap to stop a run before it overspends.

Example

models: fast haiku, strong opus        # file default
 # override: `models: act fast`  or  `models: all strong`
tier the cycle @@ -52,6 +53,17 @@

How it runs

act observe = shell check · no model
Cheap model for the thinking phases, strong model for writing code. The end-of-run summary shows the call mix per tier.
+

Example — tier plus a cost cap

+
models: fast haiku, strong opus
+observe:
+  meter tokens and cost
+  stop and warn if cost exceeds "$5"
cheap thinking, one strong act, a spend ceiling +

Common mistakes

+
    +
  • Pulling act onto the fast tier to save money. act is the phase that writes code — a weak model here produces changes that fail the check and force more cycles, costing more overall. Keep act strong and economize on plan/reflect.
  • +
  • Expecting observe to use a model. observe runs your done when shell command; it has no model tier and never appears in the cost summary. Naming a model for it does nothing.
  • +
  • Forgetting the cascade direction. A per-loop or per-stage models: line overrides the file-level one, and --model overrides them all. If a run uses the wrong tier, check the nearest scope, not just the top of the file.
  • +

Related

LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
diff --git a/docs/keywords/notify.html b/docs/keywords/notify.html index bfc6a25..9080582 100644 --- a/docs/keywords/notify.html +++ b/docs/keywords/notify.html @@ -37,11 +37,28 @@

notify

Syntax

notify: <destination>

What it does

-

Notification destination on completion (e.g. slack) — the config tier's "tell someone when it's done". Deferred past v1 for execution; parses today.

+

Declares where to send word when a run finishes — the config-tier line that answers "tell someone when it's done". It names a destination such as slack, so an unattended loop can hand its result off to a human channel instead of leaving the outcome buried in a log. It pairs naturally with schedule: and runner:: a loop you kicked off yourself you'll watch in-session, but a nightly or headless run is exactly the case where you want a ping on completion rather than checking back manually.

+

Why it lives at the config tier: notification is a property of how the file is operated, not of any single goal, so you set it once for the whole file alongside the other operational lines (schedule:, runner:, target:, runs as:). It is a delivery target only — it decides where the completion message goes, not whether the loop stopped or what "done" means. The verdict itself is still owned by done when and the human gates.

+

Status: notify: is deferred past v1 for execution — it parses today and is accepted by the grammar, so you can author it now and it won't break a run, but the delivery is not wired up yet. Treat it as a forward-looking declaration of intent rather than a guaranteed page.

Example

schedule: nightly
 notify: slack
ping on finish +

Example — on an unattended run

+
schedule: nightly
+runner: claude-code
+notify: slack
+runs as: nightly-bot
+
+loop "refresh the changelog":
+  goal: CHANGELOG.md covers everything merged since the last tag
+  done when "scripts/changelog-check.sh" passes
headless run, result pinged to a channel +

Common mistakes

+
    +
  • Expecting a message today. notify: is deferred past v1 — it parses but does not yet deliver. Don't build a workflow that depends on the ping arriving; it's an intent declaration for now.
  • +
  • Putting it inside a loop body. notify: is a config-tier line — it belongs at the top of the file with schedule: and runner:, before any loop or pipeline, not indented under a goal.
  • +
  • Treating it as a stop condition. Notification is delivery, not verification. Whether the loop is done is decided by done when and any human gate; notify: only says where to send the news.
  • +

Related

LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
diff --git a/docs/keywords/pipeline.html b/docs/keywords/pipeline.html index c2dc47b..544ef34 100644 --- a/docs/keywords/pipeline.html +++ b/docs/keywords/pipeline.html @@ -38,7 +38,8 @@

Syntax

pipeline "<name>":
   stage <name>: …

What it does

-

Runs stages in order; a failing stage halts the rest. The natural mapping: an epic → a pipeline, each story → a stage.

+

Sequences stages and runs them in order — each stage runs only if the one before it passed, and a failing stage halts the rest (fail-fast). Every stage's body is a loop: it has its own goal, its own done when, and its own back-edge, so the pipeline is really a chain of self-correcting loops with a shared thread of progress. The natural mapping is the reason it exists: an epic → a pipeline, each story → a stage. When a job is too big to verify with a single check, you don't write one giant loop — you break it into ordered stories, each with a check it can pass on its own.

+

Reach for a pipeline when the work has real ordering constraints: a security scan must pass before you build, the build must be green before a human approves the UI, the deploy runs last. Fail-fast keeps a broken early stage from wasting cycles on everything downstream, and per-stage human gates (a human approves before …) let you put a hard stop in front of the risky steps only. A pipeline needs at least one stage; the pipeline keyword sits at column 0 and each stage is indented under it with its own body indented again. For unordered work that can run at once, an inner stages in parallel: block runs its stages concurrently instead.

Example

pipeline "ship feature":
   stage security:
@@ -57,6 +58,25 @@ 

How it runs

👤 gatedeployhealth.sh ✓ each stage runs only if the one before passed — ✗ a failure halts the rest
An epic → a pipeline, each story → a stage; stages run in order with their own checks and gates.
+

Example — a gated deploy at the end

+
pipeline "epic: checkout v2":
+
+  stage "story: cart totals":
+    goal: cart shows correct totals with tax
+    look at: src/cart/, src/tax/
+    done when "pnpm test cart" passes
+
+  stage "story: checkout submit":
+    a human approves before charging the card
+    goal: order submits and payment is captured
+    done when "pnpm test checkout" passes
stories in order, a gate before the risky one +

Common mistakes

+
    +
  • A pipeline with no stages. A pipeline needs at least one stage — the pipeline is just the ordering; the stages hold the goals and checks. An empty pipeline won't parse.
  • +
  • A stage missing its own done when. Each stage is a loop and needs a way to verify itself. A stage with a goal but no check can't confirm it passed, so fail-fast can't decide whether to proceed.
  • +
  • Reaching for a pipeline when the steps are independent files. If each step runs a whole separate .loop file, that's a flow, not a pipeline. Use a pipeline for stages inside one epic; use a flow to chain files.
  • +
  • Indentation drift. pipeline at column 0, each stage indented two spaces, the stage body indented again. Mixed depth is the usual parse failure — check with loop-run show.
  • +

Related

LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
diff --git a/docs/keywords/plan-from.html b/docs/keywords/plan-from.html index 848bc48..d122688 100644 --- a/docs/keywords/plan-from.html +++ b/docs/keywords/plan-from.html @@ -38,6 +38,7 @@

Syntax

plan from "docs/plan.md"

What it does

By default the loop's plan step has the agent write the plan. plan from "<file>" overrides that: the loop reads its plan from the quoted file (a hand-written .md, say) so it executes a plan you control instead of one the agent invents. Omit it and the agent writes the plan as usual. The path is relative to the .loop file. The source is extensible — a URL or command could be added later — but the file form is the one that exists today.

+

Reach for it when the sequence of work matters and you don't want the agent to reinvent it every cycle. Common cases: a plan you wrote by hand and reviewed, a plan produced by an earlier planning loop, or a spec generated by a method (BMAD, a design doc) that you want executed verbatim. Because the plan lives in a file, it is version-controlled, diffable, and editable between runs — you tweak one step and re-run instead of re-prompting. It pairs naturally with plan, then act, then observe: the plan step still runs, but it loads your document rather than composing a fresh one, which keeps every cycle anchored to the same intent. This is the difference between directing the loop and merely launching it — a boundary-tier capability line that narrows the agent's freedom to the ordering you already decided on, while leaving act and the done when check to do the real, verifiable work.

Example

loop "execute the billing plan":
   goal: implement the plan in docs/plan.md
@@ -45,6 +46,14 @@ 

Example

each cycle: plan, then act, then observe done when "pnpm test" passes
plan from a file you control +

Common mistakes

+
    +
  • Pointing at a stale plan. The loop executes what the file says today, not what you meant last week. If the codebase moved on, the plan silently drives the agent at the wrong targets. Re-read the file before a run and edit it in place — that is the whole point of keeping the plan in version control.
  • +
  • Assuming it replaces done when. plan from only sets how the plan is chosen; it does not verify anything. You still need a real done when predicate — a controlled plan with no check is a loop that can run forever without ever proving it succeeded.
  • +
  • Wrong relative path. The quoted path resolves relative to the .loop file, not your shell's working directory. A file that exists but sits one folder over will fail to load; keep the plan next to the loop or write the correct relative path.
  • +
  • Over-specifying. A plan so detailed it dictates every edit leaves no room for reflect to adapt after a failure. Describe the ordered intent, not the exact keystrokes — let the cycle recover.
  • +
+

Related

LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
diff --git a/docs/keywords/reflect.html b/docs/keywords/reflect.html index fc49e9b..27ba06d 100644 --- a/docs/keywords/reflect.html +++ b/docs/keywords/reflect.html @@ -38,8 +38,16 @@

Syntax

when it fails: reflect, then plan again

What it does

The back-edge — the loop's working memory. On a failed check, reflect reads the failure output and writes a short diagnosis, which becomes context for the next plan. The difference between retrying blindly and learning from each miss.

+

Without a back-edge, a loop that fails its done when check simply tries again from the same starting state and tends to make the same mistake — burning tokens on a thrash. reflect breaks that cycle by inserting a diagnosis step between observe and the next plan: it names why the last cycle failed so the next plan starts from a hypothesis instead of a blank slate. You steer what it looks at with reflect on <focus> — for example reflect on which layer broke tells the agent to localize the failure to a component before re-planning. This is within-run memory; its across-run counterpart is remember in, which persists lessons to a file. Two things make reflect actually work: the failure output has to reach the next plan (end your look at: with and the last failure), and every reflect back-edge needs a floor — an after N tries: stop and warn guard — so a loop that can't diagnose its way out eventually halts instead of looping forever.

Example

when it fails: reflect on which layer broke, then plan again
the reflect back-edge +
loop "fix the checkout total":
+  goal: cart total is correct with tax and discounts
+  look at: src/cart/, src/tax/, and the last failure
+  done when "pnpm test cart" passes
+  each cycle: plan, then act, then observe
+  when it fails: reflect on which layer broke, then plan again
+  after 6 tries: stop and warn "thrashing on the total"
reflect wired into a full loop, floored by a thrash guard

How it runs

@@ -53,6 +61,12 @@

How it runs

when it fails → reflect, then plan again
Every cycle runs plan → act → observe; the done when check decides — pass → stop, fail → reflect into the next plan.
+

Common mistakes

+
    +
  • Forgetting and the last failure in look at:. reflect writes a diagnosis, but the next plan only sees it if the failure is in scope. Without that trailing item the loop reflects into a void and repeats itself — the single most common reason a reflect loop still thrashes.
  • +
  • A back-edge with no floor. when it fails: reflect, then plan again creates an unbounded retry. Always pair it with after N tries: stop and warn so a loop that can't diagnose its way out halts instead of burning tokens forever.
  • +
  • Reflecting on nothing specific. A bare reflect is fine, but reflect on <focus> aims the diagnosis (which layer, which test, which assumption). A vague focus yields a vague plan; name the axis the failure is most likely to live on.
  • +

Related

LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
diff --git a/docs/keywords/remember-in.html b/docs/keywords/remember-in.html index 63e3b2e..9924902 100644 --- a/docs/keywords/remember-in.html +++ b/docs/keywords/remember-in.html @@ -38,6 +38,7 @@

Syntax

remember in "<file.md>"

What it does

Names a Markdown file the loop treats as its memory. On start it reads the file and feeds those lessons into the first plan; on stop it appends a dated entry recording how the run went. Across runs, the loop learns from its own history instead of starting cold each time.

+

A loop forgets everything between runs. reflect gives it memory within a run — a failure feeds the next plan — but that context evaporates when the run ends. remember in is the across-run counterpart: it persists the hard-won lessons (which fix worked, which dead end to avoid, which flaky test needs a retry) to a file that survives, so the next invocation begins where the last one left off. Reach for it on loops you run repeatedly — a nightly audit, a recurring flaky-suite chase, a migration you resume over several sessions — where the same mistakes would otherwise be rediscovered each time. Because the memory is plain Markdown, it is human-readable and human-editable: you can prune stale notes, correct a wrong lesson, or seed the file with guidance before the first run. It pairs well with an after N tries guard — when a loop thrashes and stops, the memory file is exactly where the next run reads why, turning a dead end into a starting advantage instead of a repeated failure.

Example

loop "keep the flaky e2e suite green":
   goal: the end-to-end suite passes three times in a row
@@ -46,6 +47,14 @@ 

Example

each cycle: plan, then act, then observe when it fails: reflect, then plan again
a loop that carries lessons between runs +

Common mistakes

+
    +
  • Confusing it with reflect. reflect is within-run memory (a failure feeds the next plan in the same run); remember in is across-run memory (lessons persist to a file between runs). You usually want both — reflect to recover this run, remember to improve the next one.
  • +
  • Expecting memory on a one-shot loop. The value only compounds when the loop runs more than once. On a task you run a single time, the file is written but never read back — skip it and save the noise.
  • +
  • Letting the file rot. The memory is appended to on every stop, so it grows. A bloated file full of stale or contradictory notes can mislead the first plan. Prune it periodically — it is plain Markdown you own.
  • +
  • Wrong path or extension. Point at a real .md file relative to the loop; a mistyped path means lessons silently never load and never save.
  • +
+

Related

LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
diff --git a/docs/keywords/run.html b/docs/keywords/run.html index 0cb947e..808394a 100644 --- a/docs/keywords/run.html +++ b/docs/keywords/run.html @@ -40,6 +40,7 @@

Syntax

… with the result of <step>

What it does

A flow step. run "x.loop" runs every definition in that file; then run chains the next and receives the previous step's text summary; with the result of <step> pulls the handoff from a named earlier step instead of the previous one.

+

Where a loop self-corrects on one goal and a pipeline sequences stages inside a single file, a flow composes at the file level: each run executes a whole .loop — its full plan→act→observe cycle, its own done when — and passes a short text summary forward as context for the next step. Reach for it when a job spans units you already built and tested separately: a build loop, then a test loop, then a deploy loop. The chain is fail-fast — a step that ends unsatisfied halts the rest, so a broken build never reaches deploy. By default each step auto-carries the previous step's summary; with the result of <step> overrides that when a later step needs an earlier output instead (release notes that reference the build, not the test that ran after it). Paths are relative to the flow file. Add a human approves first under a step to gate it — the flow blocks until a person signs off before that file runs, which is how you put a hand on irreversible steps like a deploy.

Example

flow "release":
   run "build.loop"
@@ -54,6 +55,13 @@ 

How it runs

👤 approves first📄 deploy.loopall loops inside runs in order · ✗ a file that isn't satisfied halts the rest
A flow chains separate .loop files; after each, a short text summary carries into the next as context.
+

Common mistakes

+
    +
  • Using run outside a flow. run / then run are flow steps, not a way to invoke a loop from inside a loop or stage. To sequence stories in one file, use a pipeline with stages; use a flow only to chain whole files.
  • +
  • Wrong relative path. The quoted file resolves relative to the flow file, not your shell. A path that works from the terminal can still fail inside the flow — write it relative to where the .loop lives.
  • +
  • Assuming state carries, not just a summary. Only a short text summary passes between steps — not the file tree diff or variables. If a later step needs a specific earlier output, name it with with the result of <step> rather than hoping it survived the auto-carry.
  • +
  • Forgetting fail-fast. A step whose done when never goes green halts the entire flow. Make sure every chained file has a real, runnable check, or the chain stalls at the first weak link.
  • +

Related

LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
diff --git a/docs/keywords/schedule.html b/docs/keywords/schedule.html index 793dd59..415a264 100644 --- a/docs/keywords/schedule.html +++ b/docs/keywords/schedule.html @@ -37,11 +37,28 @@

schedule

Syntax

schedule: <when>

What it does

-

Part of the config tier — when the loop runs: manual, nightly, on push, or a cron expression. (v1 runs manual; others parse.)

+

Part of the config tier — it declares when the loop runs rather than what it does: manual, nightly, on push, or a cron expression. It sits at the top of the file, before any definition, alongside its siblings runner: (which agent executes it), target: (which directory), and notify: (where results go). Together these turn a hand-run loop into an unattended, recurring job.

+

Reach for schedule: on loops whose value comes from repetition — a nightly dependency audit, a security scan on every push, a weekly link-checker. The keyword only sets the cadence; the loop still needs a real done when check and a thrash guard, because an unattended run has no human watching each cycle. That is the point of pairing it with notify: — the loop reports its outcome to Slack or email so a failed or blocked run surfaces to a person even though nobody launched it by hand. Note the current runtime executes manual and simply parses the other cadences, so today schedule: documents intent and wires the config; treat scheduled cadences as declarative until the runner enforces them, and don't assume a nightly line alone will wake the loop up.

Example

use the audit method
 schedule: nightly
 notify: slack
a scheduled audit +
schedule: on push
+runner: claude
+target: services/api
+
+loop "gate the api on every push":
+  goal: no high-severity findings in the api service
+  done when "semgrep --severity=high services/api" finds nothing
+  after 3 tries: stop and warn "scan still failing"
a scan wired to run on push + +

Common mistakes

+
    +
  • Expecting a cadence to fire today. The v1 runtime executes manual and only parses nightly / on push / cron. A schedule: nightly line records intent but won't wake the loop yet — run it by hand or via your own scheduler until the runner enforces cadence.
  • +
  • Putting it inside a loop body. schedule: is a config-tier line — it belongs at the top of the file, before any loop / pipeline / flow. Indented under a definition it is a parse error.
  • +
  • Scheduling without a notifier. An unattended run nobody watches needs a notify: so failures reach a human. A silent scheduled loop can fail every night unnoticed.
  • +
  • No thrash guard on a recurring run. Without after N tries: stop and warn, a scheduled loop that can't reach green can loop and burn tokens with no one at the keyboard. Floor every unattended loop.
  • +

Related

diff --git a/docs/keywords/stage.html b/docs/keywords/stage.html index 312f567..51c2f84 100644 --- a/docs/keywords/stage.html +++ b/docs/keywords/stage.html @@ -38,7 +38,9 @@

Syntax

stage <name>:
   goal: …

What it does

-

One step of a pipeline. A stage's body is an ordinary loop (goal, done-when, gates, transitions) — a single story. A stage-level git: or models: block lands on that stage's loop.

+

One step of a pipeline. A stage's body is an ordinary loop — it takes the same lines a top-level loop takes (goal, done when, look at, gates, each cycle, transitions) — so a single stage is a single story with its own self-correcting cycle.

+

Reach for stages when an epic is too big to verify in one done when. Splitting it into stages gives each story its own checkable finish line, and the pipeline runs them in order: a stage that ends unsatisfied halts the ones after it, so a broken foundation never lets later work pile on top of it. That ordering is the whole point — it keeps a large piece of work honest one verifiable step at a time instead of one giant, unverifiable leap.

+

Config cascades down to a stage. A file-level each cycle:, models:, or git: block is the default for every stage; the stage overrides just itself by writing its own line. A stage-level git: or models: block lands on that stage's loop only. Put human gates on the risky stages — a human approves before … blocks that stage until someone signs off, which is where deploys and migrations belong.

Example

stage "story: email and password login":
   goal: users log in with email and password
@@ -46,6 +48,28 @@ 

Example

done when "pnpm test auth/login" passes after 8 tries: stop and warn "login story stuck"
a story stage +

Example — two stages in order

+
pipeline "epic: checkout v2":
+
+  stage "story: cart totals":
+    goal: cart shows correct totals with tax
+    look at: src/cart/, src/tax/
+    done when "pnpm test cart" passes
+    when it fails: reflect, then plan again
+
+  stage "story: checkout submit":
+    goal: order submits and payment is captured
+    a human approves before charging the card
+    done when "pnpm test checkout" passes
the cart story must pass before checkout runs + +

Common mistakes

+
    +
  • A stage outside a pipeline. Stages only exist inside a pipeline — a bare stage at column 0 won't parse. An epic is a pipeline; each story is a stage under it.
  • +
  • A stage with no done when. A stage's body is a loop, and a loop needs a checkable finish line. Without one the pipeline can't tell the story is done and can't safely advance to the next stage.
  • +
  • Wrong indentation. pipeline sits at column 0, each stage is indented under it, and the stage's own body indents another level. Mixing levels reparses your stage lines as pipeline lines.
  • +
  • Ordering hazards left ungated. Stages run top to bottom and a failure halts the rest — so put the irreversible work (a migration, a deploy) behind a human approves before … rather than letting it run unattended just because an earlier stage went green.
  • +
+

Related

LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
diff --git a/docs/keywords/target.html b/docs/keywords/target.html index 6154535..faeef3d 100644 --- a/docs/keywords/target.html +++ b/docs/keywords/target.html @@ -37,10 +37,30 @@

target

Syntax

target: <dir>

What it does

-

The working directory / scope the runner operates in — useful with a method or a scheduled run to point the loop at a specific codebase or subtree.

+

target: names the working directory the runner operates in — the root it plans, edits, and runs its done when command from. It's a config-tier line: it sits at the top of the file, before any loop or pipeline, and applies to every definition below it.

+

Why reach for it? Most of the time you run a .loop from the repo root and the target is implicit. You set target: when the loop shouldn't operate on the whole checkout — a monorepo where the work lives in one package, a scheduled or unattended run that has no interactive cwd to inherit, or a method (like BMAD) whose stages should scope to a subtree instead of the entire tree. Pointing the runner at the smallest directory that still contains the work keeps its context tight and stops it from wandering into unrelated code.

+

target: is about where the runner stands, which is coarse; look at: is about which files it reads, which is fine-grained. They compose: target picks the subtree, look at: narrows the agent's attention within it. Quote paths exactly — a relative path resolves against the loop file's own location.

Example

use the BMAD method
-target: ./src
scope to a subtree +target: ./src
scope a method to a subtree + +

Example — target with a schedule

+
schedule: every weekday at 7am
+runner: claude code
+target: ./services/billing
+
+loop "keep billing deps current":
+  goal: no known-vulnerable dependencies in the billing service
+  done when "pnpm audit --audit-level=high" finds nothing
+  after 4 tries: stop and warn "needs a human"
an unattended run scoped to one service + +

Common mistakes

+
    +
  • Putting target: inside a loop body. It's a config-tier line — it belongs at the top of the file, above the first definition. Nested under a loop it's out of place.
  • +
  • Confusing it with look at:. target: sets the runner's directory; look at: lists the files the agent reads. Scoping the subtree does not replace pointing the agent at the right files.
  • +
  • A done when command that assumes the repo root. The predicate runs from the target directory. If your command's paths were written for the repo root, they'll miss once the runner is scoped to a subtree — write them relative to the target.
  • +
  • Relying on it interactively when the cwd already fits. Running from the repo root, target: is redundant. Its real value is unattended and scheduled runs, or a monorepo subtree — don't add it just to restate where you already are.
  • +

Related

diff --git a/docs/keywords/use-method.html b/docs/keywords/use-method.html index 7adcc81..b0303b6 100644 --- a/docs/keywords/use-method.html +++ b/docs/keywords/use-method.html @@ -37,12 +37,30 @@

use the <X> method

Syntax

use the <X> method

What it does

-

Pulls in a method — a library of stages (e.g. BMAD's analyze → architect → story → qa) — so a tiny file behaves like a hand-written pipeline. Methods are libraries, not syntax: import behavior instead of repeating stages.

+

Pulls in a method — a library of stages (e.g. BMAD's analyze → architect → story → qa) — so a tiny file behaves like a hand-written pipeline. Methods are libraries, not syntax: you import proven behavior instead of retyping the same stages in every file.

+

Why it matters: a mature workflow is a fixed sequence of stories with the same gates and checks every time. Copy-pasting that pipeline into every .loop is error-prone and drifts as the method evolves. use the <X> method collapses the whole sequence into one line — the method supplies the stages, their order, and their default gates; your file just declares intent. It's a config-tier line, so it belongs at the top of the file, above any definition, alongside companions like runner: and target:.

+

A method preset can also carry its own git: block — a version-control strategy the whole imported pipeline runs under. That default is the weakest tier: your file's own git: block, or a per-loop one, overrides it. Because a method is a plain library of stages, it stays method-neutral — BMAD is one example, not the syntax; the same mechanism imports any stage library that ships for Loop.

Example

use the BMAD method   # import the method's whole pipeline
-run with claude code
+runner: claude code
 target: ./src
examples/methods/use-bmad.loop +

Example — override the method's git default

+
use the BMAD method       # preset may carry its own git: block
+target: ./packages/api
+
+git:
+  work in a worktree       # this file wins over the method's default
+  commit each story
the file's git: block overrides the preset's + +

Common mistakes

+
    +
  • Writing it inside a loop body. use the <X> method is config-tier — it goes at the top of the file, before any loop or pipeline. It imports a pipeline; it isn't a line you put inside one.
  • +
  • Assuming the method's git: block is final. A preset's git strategy is the lowest tier of the cascade. If you need a different branch or commit cadence, add your own git: block — it overrides the method's.
  • +
  • Expecting new syntax. A method is a stage library, not a keyword — it can't do anything a hand-written pipeline couldn't. If you need to see the shape it expands to, print the flow.
  • +
  • Treating it as BMAD-only. The mechanism is method-neutral. Name whichever method's library ships for your project; don't assume BMAD is the only value the line accepts.
  • +
+

Related

LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
diff --git a/docs/keywords/use-skills.html b/docs/keywords/use-skills.html index 280da5f..91707f7 100644 --- a/docs/keywords/use-skills.html +++ b/docs/keywords/use-skills.html @@ -37,7 +37,9 @@

use skills

Syntax

use skills: <skill-a>, <skill-b>

What it does

-

Lists skills the agent is allowed to call while it works — so the loop coordinates proven, reusable skills instead of one mega-prompt. Pair it with done when the skill "<name>" approves to let a review skill decide the verdict.

+

Lists the skills the agent is allowed to call while it plans and acts — so the loop coordinates proven, reusable skills instead of one giant prompt. This is skill-driven development: you build and battle-test each skill on its own, then wire the loop to orchestrate them. The names must already resolve (in ~/.claude/skills); if they don't exist yet, prove the skill by hand first, then add it here.

+

Why it matters: a monolithic prompt is hard to debug and impossible to reuse. Naming skills keeps each capability small, independently tested, and shared across loops — the loop's job shrinks to deciding when to call each one. There are two roles a skill can play, and they're distinct. As an execution skill listed under use skills:, it's a tool the agent may invoke during a cycle. As a verifier, it decides the verdict via done when the skill "<name>" approves (or scores 8 or more, or approves by 3 judges). Pairing the two — an execution skill that does the work and a review skill that judges it — is the common shape.

+

If the skills don't exist locally, let a recommender install them: use skills recommended by ctx resolves the bundle at run time (with recommend skills with ctx at the config tier). With no ctx attached those lines are inert and the loop runs unchanged.

Example

loop "harden the upload endpoint":
   goal: no high-severity findings in the upload path
@@ -46,6 +48,23 @@ 

Example

each cycle: plan, then act, then observe when it fails: reflect, then plan again
a loop that drives two named skills +

Example — skills chosen by ctx

+
recommend skills with ctx              # config tier: ctx is the skill source
+
+loop "harden the stripe webhook handler":
+  goal: webhook retries are idempotent and signature-checked, with tests
+  use skills recommended by ctx for "stripe webhook idempotency"
+  top up skills from ctx when a step needs more
+  done when "pnpm test api/webhooks" passes
let ctx pick + install the bundle + +

Common mistakes

+
    +
  • Naming a skill that doesn't exist. use skills: assumes the names resolve in ~/.claude/skills. Inventing a skill around capabilities you haven't built means the loop calls nothing. Prove the skill manually first, or let ctx install it.
  • +
  • Confusing the execution role with the verifier role. Listing a skill under use skills: only permits the agent to call it — it does not make it the finish line. To let a skill decide "done", it must appear in a done when the skill "…" approves predicate.
  • +
  • Trusting a green test alone when "done" also means "built right". An execution skill can make a test pass the wrong way. Add a trajectory eval — done when the skill "…" approves on the trajectory with a the bar: line — to judge how the work was done, not just the result.
  • +
  • Assuming ctx lines do something without ctx. use skills recommended by ctx is inert unless the ctx MCP server is attached; it won't error, but it also won't install anything. For a self-contained file, list the resolved skills under use skills:.
  • +
+

Related

LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
diff --git a/docs/keywords/when.html b/docs/keywords/when.html index f582a10..6037585 100644 --- a/docs/keywords/when.html +++ b/docs/keywords/when.html @@ -39,7 +39,9 @@

Syntax

when it fails: reflect, then plan again when blocked: ask a human

What it does

-

when … rules run after each observe. Conditions: it passes · it passes and the goal is met · it fails · blocked. Actions: stop · stop and warn · reflect · plan · act · observe · ask a human. Precedence is fixed: blocked > attempts > pass > fail.

+

when … rules are the loop's transitions — they run after each observe and decide what happens next. Conditions: it passes · it passes and the goal is met · it fails · blocked. Actions: stop · stop and warn · reflect · plan · act · observe · ask a human.

+

These lines are what make a loop self-correcting rather than a one-shot prompt. when it fails: reflect, then plan again is the back-edge: it turns a failed check into a diagnosis that feeds the next plan, so the loop learns within a run instead of repeating the same mistake. For that diagnosis to reach the next plan, end look at: with and the last failure. when blocked: ask a human is the escape hatch for when the agent genuinely can't proceed. Together they cover the three outcomes of every cycle: done, retry, or stuck.

+

Precedence is fixed by the engine, not by the order you write the lines: blocked > attempts > pass > fail. That ordering is deliberate — after N tries (attempts) is checked before it fails, so once you hit the try ceiling the thrash guard always wins and a failing loop can't reflect-and-retry forever. Never write a reflect back-edge without also giving the loop a hard stop; the last line of a loop is its ceiling.

Example

when it passes and the goal is met: stop
 when it fails: reflect on which layer broke, then plan again
@@ -57,6 +59,13 @@ 

How it runs

4it fails? reflect, then plan again
The order is the engine's, not yours: attempts is checked before fail, so the thrash guard always wins once you hit the limit.
+

Common mistakes

+
    +
  • A when it fails back-edge with no ceiling. Reflect-and-plan-again with no after N tries is an infinite, token-burning loop. The last line of every loop should be its hard stop — pair the back-edge with a thrash guard.
  • +
  • Expecting write order to change precedence. The engine evaluates blocked > attempts > pass > fail no matter how you order the lines. You can't make it fails outrank after N tries by writing it first.
  • +
  • Reflecting without passing the diagnosis forward. reflect only helps the next plan if it can read the failure — end look at: with and the last failure, or the reflection is discarded and the loop repeats itself.
  • +
  • Confusing it passes with it passes and the goal is met. A cycle's check can pass while the overall goal isn't met yet. Use it passes and the goal is met: stop for the real finish line, not a bare it passes that stops too early.
  • +

Related

LoopFlow · the keyword reference. New here? Start with the tutorial or learn by playing LoopFlow Lab.
From 05f3f17fe3cd2e0fea16514a3cfe6d8023878f03 Mon Sep 17 00:00:00 2001 From: tickets-forge-dev Date: Sun, 5 Jul 2026 00:59:21 -0400 Subject: [PATCH 7/9] seo(blog): add /blog with 3 query-targeted articles + index MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New indexable ranking + GEO assets, each targeting a real search query and grounded in AGENTS.md (runnable .loop examples, links into the docs): - what-is-an-ai-coding-loop — definitional (opens with a quotable definition for LLM citation); targets "AI coding loop" - make-claude-code-self-correct — how-to; targets "make Claude Code self-correct" - one-shot-prompts-vs-self-correcting-loops — comparison; targets "prompt vs loop" Each page is SEO-complete (canonical, OG, Twitter, BlogPosting JSON-LD, analytics, one H1) and 1000+ words. Adds blog/index.html (Blog schema), links it from the homepage nav, and registers all 4 URLs in sitemap.xml (30 -> 34). Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/blog/index.html | 39 +++++ docs/blog/make-claude-code-self-correct.html | 101 +++++++++++++ ...shot-prompts-vs-self-correcting-loops.html | 102 +++++++++++++ docs/blog/what-is-an-ai-coding-loop.html | 137 ++++++++++++++++++ docs/index.html | 1 + docs/sitemap.xml | 4 + 6 files changed, 384 insertions(+) create mode 100644 docs/blog/index.html create mode 100644 docs/blog/make-claude-code-self-correct.html create mode 100644 docs/blog/one-shot-prompts-vs-self-correcting-loops.html create mode 100644 docs/blog/what-is-an-ai-coding-loop.html diff --git a/docs/blog/index.html b/docs/blog/index.html new file mode 100644 index 0000000..5f1ea5c --- /dev/null +++ b/docs/blog/index.html @@ -0,0 +1,39 @@ + + + + +LoopFlow blog — self-correcting AI coding loops, explained + + + + + + + + + + + + + + + + + + + +
+

LoopFlow blog

+
Guides on self-correcting AI coding loops, AI agents, and loop engineering — every post grounded in a real, runnable .loop.
+

What is an AI coding loop?

A self-correcting AI agent that plans, acts, and re-runs a real verification check until the proof is green — not a one-shot prompt you have to babysit.

+

How to make Claude Code self-correct

Claude Code does one pass and stops; a .loop gives it a verifiable finish line and a reflect back-edge so it retries until the tests actually pass.

+ + +
\ No newline at end of file diff --git a/docs/blog/make-claude-code-self-correct.html b/docs/blog/make-claude-code-self-correct.html new file mode 100644 index 0000000..a962825 --- /dev/null +++ b/docs/blog/make-claude-code-self-correct.html @@ -0,0 +1,101 @@ + + + + +How to Make Claude Code Self-Correct | LoopFlow + + + + + + + + + + + + + + + + + + + +
+
Blog / Make Claude Code self-correct
+

How to make Claude Code self-correct

+
Claude Code does one pass and stops; a .loop gives it a verifiable finish line and a reflect back-edge so it retries until the tests actually pass.
+

Claude Code does one pass and stops. To make it self-correct — retry until the tests actually pass — you need a verifiable finish line and a back-edge that feeds each failure into the next attempt. That is exactly what a .loop file is.

+ +

The problem: agents do one pass and stop

+

Ask Claude Code to "fix the failing checkout test" and it edits some code, runs the suite once (maybe), and replies "Done — fixed the rounding." Sometimes it's right. Often the test is still red, or a different test broke, or it never ran the suite at all. "Done" is whatever the model said, not a command that passed.

+

The fix isn't a better prompt. A prompt fires once and trusts the model's word. What you want is a control loop: the agent acts, a real check grades the result, and on red the agent tries again — with the failure in hand — until the check is green or a ceiling stops it. That control loop is the artifact you edit, not the prose.

+ +

What "self-correcting" actually means

+

A self-correcting run is four repeating steps wrapped around a verdict the model can't author:

+
    +
  • plan — read the scoped context, decide the smallest change toward the goal.
  • +
  • act — make the change.
  • +
  • observe — run the done when check and read pass/fail.
  • +
  • reflect — on red, diagnose why it failed and feed that into the next plan.
  • +
+

The load-bearing part is observe. At that step the runtime — plain deterministic code, not the LLM — spawns your check as a real OS process and reads the exit code from the operating system. Exit 0 = pass; anything else = fail. The model does the work; the OS grades it. That's why "done" can't be faked: the verdict never comes out of the model's mouth.

+

The other load-bearing part is reflect, the back-edge. Without it, a retry is just the same blind attempt again. With it, cycle two reads what broke in cycle one. That is the difference between a loop that thrashes and one that converges.

+ +

A concrete walkthrough

+

Say the checkout tax test is red. Here is the whole self-correcting loop — the finish line at the top, the safety net at the bottom:

+
loop "fix the checkout tax test":
+  goal: the checkout tax test passes with no regressions
+  done when the test "checkout.spec.ts::tax" passes
+
+  look at: src/checkout, and the last failure
+  allow edits automatically, but ask me before pushes
+
+  each cycle: plan, then act, then observe
+  when it fails: reflect on which layer broke, then plan again
+  after 6 tries: stop and warn "tax fix thrashing"
+

Every cycle runs the named test. Red → reflect writes a one-line diagnosis ("rounding happens before the discount, not after") → that becomes context for the next plan. The loop stops only when the process your machine ran returns 0. It works on a branch and, with no git: block, never pushes to main.

+

Two lines earn their keep. look at: ends with and the last failure — reflect's diagnosis only reaches the next plan if you pass it forward. And after 6 tries is the floor: a back-edge with no ceiling is a token bonfire. Never write one without the other.

+

The check doesn't have to be a test. Any command that exits non-zero on failure works, and you can list several — all must pass:

+
loop "harden the auth middleware":
+  goal: rate limiting works and no high-severity findings remain
+  done when "pnpm test src/auth" passes
+  done when "semgrep --severity=high" finds nothing
+
+  look at: src/auth, and the last failure
+  each cycle: plan, then act, then observe
+  when it fails: reflect, then plan again
+  after 8 tries: stop and warn "auth loop stuck"
+

finds nothing means "this scanner must report zero" — exit 0 and empty output. Stacking a test with a scan is how you make one loop prove both "it works" and "it's clean."

+ +

How to run it

+

Install once, then two ways to drive it:

+
npx @loop-lang/loop init      # writes the /loopflow skill + AGENTS.md into your repo
+
    +
  • In a Claude Code chat/loopflow run fix-tax.loop. You watch every plan → act → observe → reflect step and answer human gates inline. With init, Claude also reaches for a .loop on its own when work is repeatable and verifiable — you often don't type the slash at all.
  • +
  • Headlessloop-run run fix-tax.loop in a terminal or CI. Print the shape first with loop-run show fix-tax.loop; a missing done-when or thrash guard is obvious in the ASCII.
  • +
+

A .loop is plain text, so the same file works in Cursor or Copilot — point the agent at AGENTS.md and it reads the goal, the check, and the stopping rules the same way Claude Code does.

+ +

Common pitfalls

+
    +
  • No real check. A loop with no done when has nothing to self-correct against — it just runs to the cap. Write the check before the behavior; if you can't, you don't understand the goal yet.
  • +
  • A test runner that exits 0 on failure. The check runs with your privileges in your shell. If it lies about success, the loop lies to you. Run the command by hand once before trusting it.
  • +
  • Dropping the failure. Forget and the last failure and every cycle re-plans blind. That's a retry, not self-correction.
  • +
  • A back-edge with no ceiling. reflect, then plan again without after N tries can burn tokens on an unfixable goal. The engine caps every loop at 25 cycles regardless, but set your own floor with a message that tells future-you what got stuck.
  • +
  • Unbounded scope. look at: the whole repo makes the agent wander and rewrite working code. Name the three files that matter.
  • +
+ +

Wrap-up

+

Making Claude Code self-correct isn't a trick — it's structure. A goal, a check the OS grades, a reflect back-edge, and a try ceiling turn one-shot prompting into a loop that retries until the tests pass and stops when they do. Write it once, re-run it forever, review it in a PR.

+

Try it now in the playground, or learn the whole language line by line in the tutorial.

+ +
\ No newline at end of file diff --git a/docs/blog/one-shot-prompts-vs-self-correcting-loops.html b/docs/blog/one-shot-prompts-vs-self-correcting-loops.html new file mode 100644 index 0000000..c958a66 --- /dev/null +++ b/docs/blog/one-shot-prompts-vs-self-correcting-loops.html @@ -0,0 +1,102 @@ + + + + +One-Shot Prompts vs Self-Correcting Loops | LoopFlow + + + + + + + + + + + + + + + + + + + +
+
Blog / One-shot prompts vs loops
+

One-shot prompts vs self-correcting loops

+
A one-shot prompt asks an AI coding agent for an answer and trusts the reply; a self-correcting loop verifies, retries on red, and stops only on proof.
+

Two ways to point an AI coding agent at a task

+

A one-shot prompt is the default: you describe the change, the AI coding agent edits some files, replies "Done", and the turn ends. A self-correcting loop is the other shape: you describe the change and a machine-checkable definition of finished, and the agent plans, acts, checks its own work, and keeps going until the check is green — or stops and warns you it's stuck.

+

The difference isn't the model or the prompt quality. It's the control structure wrapped around the model. One fires once and trusts the reply. The other verifies, reflects on failure, and only stops on proof. This post walks the trade-off and shows both — because a loop isn't always the right call.

+ +

Where one-shot prompts break down

+

A one-shot prompt has one structural flaw, and everything else follows from it: there is no verification step the agent must pass. The agent decides when it's done, and it announces done whether or not the work is done.

+
    +
  • "Done" is a claim, not a result. The agent says the test passes. Did you run it? A one-shot prompt stops when the model stops typing, not when the suite goes green.
  • +
  • Failure is your job to catch. You notice the regression, re-read the diff, re-type the prompt, and hope the second try lands. The retry loop exists — it's just running in your head and your keyboard.
  • +
  • Nothing bounds the actions. On the way to "done" the agent might edit files you didn't mean to touch, weaken a test to make it pass, or run git push. A prompt can ask it to be careful; it can't enforce it.
  • +
  • It doesn't compound. The next person re-types a slightly different paragraph and gets slightly different behavior. There's no artifact to review, diff, or re-run.
  • +
+

None of this means the model is bad. It means an unverified single shot is the wrong container for work where "done" actually has to be true.

+ +

What a self-correcting loop adds

+

A .loop file adds exactly the four things a one-shot prompt is missing — a checkable finish line, a failure back-edge, gates on risk, and a floor so it can't spin forever.

+
    +
  • A verifiable finish line. done when names a real command — a test, a scanner, a script. At the observe step the runtime (deterministic code, not the model) spawns that command as an OS process and reads the exit code. Exit 0 = pass. The model does the work; the OS grades it. You can't fake an exit code.
  • +
  • Self-correction on failure. When the check fails, reflect reads the failure output, writes a short diagnosis, and feeds it into the next plan. That back-edge is what makes it self-correcting instead of an agent that retries blindly.
  • +
  • Human gates on the risky steps. ask me before … and a human approves before … put a person in front of migrations, deploys, anything irreversible — and by default a loop works on a branch and never pushes to main or master.
  • +
  • A thrash guard. after N tries: stop and warn is the floor. An unfixable goal stops burning tokens and tells you what got stuck, instead of looping forever.
  • +
+ +

Side by side: the same task, both ways

+

The one-shot prompt:

+

"Fix the failing checkout tax test in src/checkout and make sure nothing else breaks." The agent edits, replies "Done — fixed the rounding." Did checkout.spec.ts::tax pass? The whole suite? You re-run it yourself. Failed? Re-prompt. And it may have pushed on the way.

+

The same task as a self-correcting loop:

+
loop "fix the checkout tax test":
+  goal: the checkout tax test passes with no regressions
+  done when the test "checkout.spec.ts::tax" passes
+
+  look at: the checkout code, and the last failure
+  allow edits automatically, but ask me before pushes
+
+  each cycle: plan, then act, then observe
+  when it fails: reflect, then plan again
+  after 6 tries: stop and warn "tax fix thrashing"
+

It runs the test every cycle. Fails, reflects on why, fixes again. Stops only when the test is green — or warns after six. Works on a branch, never touches main. The same file runs tomorrow, and a teammate can read exactly what "done" meant.

+

You can stack the finish line for work where one green isn't enough. Multiple done when lines are a conjunction — all must pass:

+
loop "harden the auth middleware":
+  goal: sessions expire correctly and no high-severity findings remain
+  done when "pnpm test src/auth" passes
+  done when "semgrep --severity=high" finds nothing
+
+  look at: the auth middleware, and the last failure
+  allow edits automatically, but ask me before touching migrations
+
+  each cycle: plan, then act, then observe
+  when it fails: reflect on which check broke, then plan again
+  when blocked: ask a human
+  after 8 tries: stop and warn "auth hardening stuck"
+

A one-shot prompt can describe both conditions. Only the loop enforces them, cycle after cycle, and self-corrects toward both.

+ +

When a one-shot prompt is still the right call

+

Loops cost more — every cycle re-plans and re-runs the check, and that's tokens and wall-clock. Don't wrap ceremony around work that doesn't need it. A one-shot prompt wins when any of these hold:

+
    +
  • The task is one-off. Rename a variable, tweak copy, answer a question about the codebase. Nothing repeats, so there's nothing to reuse.
  • +
  • "Done" isn't checkable. If you can't write the finish line as a test, a command, or an explicit human review, a loop has nothing to verify against — it degrades to a one-shot with extra steps.
  • +
  • The iterations aren't worth it. A trivial edit you can eyeball in a diff doesn't earn a plan-act-observe cycle.
  • +
+

The rule of thumb is the four-condition gate: does the task repeat, is "done" checkable, are the iterations affordable, and can the loop verify itself? All four hold → reach for a loop. Any one fails → just prompt, and move on.

+ +

The takeaway

+

A one-shot prompt asks the AI coding agent for an answer. A self-correcting loop asks for a result and won't stop until a real check agrees. Use the prompt for the trivial and the one-off. Reach for the loop the moment "done" has to be provably true, the agent should retry on its own, and a human needs to gate the dangerous step. Same model — a container that verifies instead of hoping.

+

Try both shapes side by side in the playground, or learn the whole language from the first line in the tutorial.

+ +
\ No newline at end of file diff --git a/docs/blog/what-is-an-ai-coding-loop.html b/docs/blog/what-is-an-ai-coding-loop.html new file mode 100644 index 0000000..4c5d541 --- /dev/null +++ b/docs/blog/what-is-an-ai-coding-loop.html @@ -0,0 +1,137 @@ + + + + +What Is an AI Coding Loop? A LoopFlow Explainer + + + + + + + + + + + + + + + + + + + +
+
Blog / What is an AI coding loop?
+

What is an AI coding loop?

+
A self-correcting AI agent that plans, acts, and re-runs a real verification check until the proof is green — not a one-shot prompt you have to babysit.
+

An AI coding loop is a workflow in which an AI agent repeatedly plans a change, makes it, and runs a real verification check — feeding each failure back into the next attempt — until the check passes or a retry ceiling stops it. It replaces the fire-once prompt with a self-correcting cycle that stops on proof, not on the model's say-so.

+ +

Put another way: a one-shot prompt asks for an answer and trusts the reply. An AI coding loop asks for a result and won't stop until a command your machine ran agrees the result is there. The loop is the control structure; the model is just the worker inside it.

+ +

The anatomy of an AI coding loop

+ +

Every self-correcting AI agent loop, whatever the tooling, is built from the same five parts. In LoopFlow — a small natural-language DSL for writing these loops as .loop files — each maps to one line:

+ +
    +
  • A goal — what "done" means, in plain language. The goal is the objective the agent is working toward.
  • +
  • Context — the files and prior failure the agent may read before it acts. Scoping this keeps the agent in your module instead of wandering the whole repo.
  • +
  • Actions — what the agent may do on its own, and what needs a human. Risky, irreversible work (migrations, deploys, pushes) gets gated.
  • +
  • Verification — the check that decides pass or fail. In LoopFlow this is done when, and it runs a real command.
  • +
  • Stopping — when to quit: the goal is met, or the loop has thrashed past a try ceiling.
  • +
+ +

The engine that ties them together is a repeated cycle: plan (decide the smallest change), act (make it), observe (run the check). On a red check the loop reflects — it reads the failure output, writes a short diagnosis, and hands that to the next plan. That back-edge is what makes the agent self-correcting rather than blindly retrying.

+ +

Why a loop beats a one-shot prompt

+ +

A single prompt fires once and stops when the model stops typing. You are the verification step: you re-run the test, notice it failed, and re-prompt — every time. The failure mode is silent. The model replies "Done — fixed the rounding," and you find out later that the test never went green.

+ +

An AI coding loop closes that gap on three fronts:

+ +
    +
  1. "Done" is provable. The verdict never comes from the model. At the observe step, deterministic runtime code spawns your check as a real OS process and reads the exit code. Exit 0 = pass; anything else = fail. The agent does the work; the operating system grades it.
  2. +
  3. Failure is fuel, not a dead end. A red check triggers a reflect-and-replan instead of a stop. The loop learns from each miss automatically.
  4. +
  5. Risk is gated, scope is bounded. The agent works on a branch, never pushes to main/master, and pauses at the gates you set.
  6. +
+ +

A concrete .loop, walked through

+ +

Here is a complete AI coding loop for a failing test. Every line is one of the five parts above:

+ +
loop "fix the checkout tax test":
+  goal: the checkout tax test passes with no regressions
+  done when the test "checkout.spec.ts::tax" passes
+
+  look at: the checkout code, and the last failure
+  allow edits automatically, but ask me before pushes
+
+  each cycle: plan, then act, then observe
+  when it fails: reflect, then plan again
+  after 6 tries: stop and warn "tax fix thrashing"
+ +

Reading it top to bottom — the finish line first, the safety net last:

+ +
    +
  • goal and done when are the contract. The check is written before any behavior — if you can't state the check, you don't yet know what you're building.
  • +
  • look at and allow … ask me before … are the boundaries: what the agent may read, and what it may do alone. Ending look at with and the last failure is what feeds the reflect diagnosis into the next plan.
  • +
  • each cycle is the engine — the repeated plan → act → observe unit.
  • +
  • when it fails and after 6 tries are the safety net: recovery, then a hard floor so the loop can never spin forever. (LoopFlow also enforces an absolute cap of 25 cycles regardless.)
  • +
+ +

Run it and the loop runs the test every cycle. Red? It reflects on why, edits, and re-checks. It stops only when checkout.spec.ts::tax is green — or warns after six attempts. The same file works tomorrow, and a teammate can read exactly what "done" meant.

+ +

Verification is the whole trick

+ +

The check is the loop's definition of reality, so it has to be real. LoopFlow supports several predicate forms, and you can list as many as you need — all must pass:

+ +
loop "harden the auth module":
+  goal: auth is covered and free of high-severity findings
+  done when "pnpm test src/auth" passes            # a shell command, exit 0
+  done when "semgrep --severity=high" finds nothing # exit 0 AND empty output
+  done when the skill "code-review" approves         # an LM-judge eval
+
+  look at: src/auth, and the last failure
+  each cycle: plan, then act, then observe
+  when it fails: reflect, then plan again
+  after 8 tries: stop and warn "auth hardening stuck"
+ +

The command runs in your shell with your privileges — treat a .loop from an untrusted source as you would their shell scripts. A test runner that exits 0 on failure will make the loop lie to you, so write the check like you mean it.

+ +

Where AI coding loops scale

+ +

One loop fixes one thing. Real work is a sequence of them, and LoopFlow composes loops two ways:

+ +
    +
  • A pipeline is an epic broken into stages — each stage is itself a loop with its own goal and check, and stages run in order; a failing stage halts the rest. You can gate a stage on a human (a human approves before charging the card) for the risky steps.
  • +
  • A flow chains whole .loop files, passing each step's text result forward as context for the next — build, then test, then deploy behind an approval.
  • +
+ +

Because each stage carries its own verification, a multi-step AI agent workflow degrades safely: the pipeline can only advance past a stage whose check actually went green.

+ +

How to run one

+ +

With LoopFlow installed (npx @loop-lang/loop init), there are two surfaces:

+ +
    +
  • In a Claude Code chat via the /loopflow skill — describe the work and it authors the .loop, then /loopflow run <file>.loop runs it natively in the session. You watch every plan → act → observe → reflect step and answer human gates inline.
  • +
  • Headless via the CLI — loop-run run <file>.loop to execute, or loop-run show <file>.loop to print the shape and catch a missing check or thrash guard before you run it.
  • +
+ +

The default installed into CLAUDE.md means you rarely type the slash: ask for something repeatable and verifiable and the agent reaches for a loop on its own; ask a one-off question and it just answers.

+ +

The takeaway

+ +

An AI coding loop is the difference between an agent that claims it finished and one that keeps working until the world agrees it did. Give it a goal, scope its context, gate the risky actions, hand it a check it can't fake, and cap the retries — and you get a self-correcting AI agent you can leave running, review in a PR, and re-run tomorrow.

+ +

Try it: write a .loop and watch its shape in the playground, or learn the whole language line by line in the tutorial.

+ +
\ No newline at end of file diff --git a/docs/index.html b/docs/index.html index ce02239..7d5fe84 100644 --- a/docs/index.html +++ b/docs/index.html @@ -253,6 +253,7 @@
  • Go deeper
  • 📖 Full manual →
  • 📖 Keyword reference →
  • +
  • ✍️ Blog →
  • ⚡ Playground →
  • 🛠️ Workshop →
  • 🎮 LoopFlow Lab →
  • diff --git a/docs/sitemap.xml b/docs/sitemap.xml index 54fcd80..0bce932 100644 --- a/docs/sitemap.xml +++ b/docs/sitemap.xml @@ -30,4 +30,8 @@ https://loopflow.live/keywords/use-method.html https://loopflow.live/keywords/use-skills.html https://loopflow.live/keywords/when.html + https://loopflow.live/blog/ + https://loopflow.live/blog/what-is-an-ai-coding-loop.html + https://loopflow.live/blog/make-claude-code-self-correct.html + https://loopflow.live/blog/one-shot-prompts-vs-self-correcting-loops.html From 677fa662c19b4d9c8485988beeb42710ac7c77e9 Mon Sep 17 00:00:00 2001 From: tickets-forge-dev Date: Sun, 5 Jul 2026 01:03:10 -0400 Subject: [PATCH 8/9] seo(blog): add 'I Was the For-Loop' essay as a styled post Convert the existing docs/blog/i-was-the-for-loop.md draft into a full, SEO-complete blog page (canonical, OG, Twitter, BlogPosting JSON-LD, analytics); add it to the blog index (now 4 posts) and sitemap.xml (34 -> 35 URLs). The markdown source is kept. Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/blog/i-was-the-for-loop.html | 88 +++++++++++++++++++++++++++++++ docs/blog/index.html | 1 + docs/sitemap.xml | 1 + 3 files changed, 90 insertions(+) create mode 100644 docs/blog/i-was-the-for-loop.html diff --git a/docs/blog/i-was-the-for-loop.html b/docs/blog/i-was-the-for-loop.html new file mode 100644 index 0000000..d442df5 --- /dev/null +++ b/docs/blog/i-was-the-for-loop.html @@ -0,0 +1,88 @@ + + + + +I Was the For-Loop | LoopFlow + + + + + + + + + + + + + + + + + + + +
    +
    Blog / I was the for-loop
    +

    I Was the For-Loop

    +
    I thought I missed writing code. Turns out I missed deciding — and that part you can get back.
    +

    I thought I missed writing code. Turns out I missed deciding — and that part you can get back.

    +

    I don't miss writing code. Not really.

    +

    I missed something, for months, and I kept calling it "writing code" because that was the nearest word. Saying otherwise sounds like the setup to a tool pitch, so let me just show you the conclusion I backed into — I resisted it for a long time.

    +

    What I thought I missed

    +

    The typing.

    +

    Specifically, the way the act of typing finishes the thought. You have the shape of a function half-formed in your head, you start writing it, and the writing is the thinking. The code teaches you what you meant. You rename one variable and the whole design clicks into a better shape you couldn't see from the outside. Hours go like that.

    +

    That's what I reached for when I felt the absence. And here's the part that took me too long to admit: reaching for it was a dead end. The model writes the code now, it writes it well, and when it doesn't it's usually because I was vague, not because it couldn't type. I tried the obvious cure — turn the AI off for the hard parts, do those by hand. I lasted about a week. It felt good, it was slower, and it produced nothing the machine wouldn't have. It felt like nostalgia wearing the costume of principle.

    +

    So the typing wasn't it. I'd confused the instrument for the music.

    +

    What actually went missing

    +

    Every coding task is five decisions. What done means. What the work is allowed to touch. What actions it can take on its own. How you'll know it actually worked. And when to stop.

    +

    I used to make all five with my hands on the keyboard, without noticing — they were dissolved into the act of building. When the model took over the building, those five decisions didn't get promoted to me. They got buried. Smeared across a long prompt, a few "actually, also—" follow-ups, and a lot of me squinting at output going "no, not like that." I was still making every decision. I just couldn't see them anymore, so it stopped feeling like mine.

    +

    2am

    +

    The night it cracked open, I was on a flaky test. One run in five, red. The agent fixed it, green, I exhaled, three runs later red again because the fix was a guess in a trenchcoat.

    +

    I watched myself work and I wasn't typing. I was scrolling. Reading a diff, nodding at the good parts, frowning at a setTimeout that smelled like a band-aid. Re-pasting the stack trace. Re-explaining the same context for the fourth time. Third loop, the agent started editing the test to make the failure go away.

    +

    Somewhere in there it landed: I was the for-loop. I was the exit condition. I was holding the whole control structure in my tired head and feeding it to the model one soggy prompt at a time. Plan, act, observe; it failed, so reflect, then plan again — me, by hand, at 2am, badly.

    +

    The honest version is worse. I never told it what a fix was. I never said which layer I suspected. I never set a ceiling on retries. I'd handed over the actions and kept none of the authorship — and then I was surprised it felt like babysitting.

    +

    So I wrote the loop down

    +

    Not the code. The loop. The five decisions, out of my head and onto the page:

    +
    • Goal — the apostrophe bug: settings save when the company name has one.
    • Context — the form, the API route, the last failure. Not the whole repo.
    • Actions — edit freely, but ask me before a migration or a push.
    • Check — the regression test goes green. Not "looks done." Green.
    • Stop — after six tries, quit and tell me it's thrashing.
    +

    Written as a thing the machine can run, that's this:

    +
    loop "fix billing apostrophe bug":
    +  goal: settings save when the company name has an apostrophe
    +  done when the test "billing.spec.ts::apostrophe" passes
    +  look at: billing/form.tsx, api/settings.ts, and the last failure
    +  allow edits automatically, but ask me before migrations or pushes
    +  each cycle: plan, then act, then observe
    +  when it fails: reflect on which layer broke, then plan again
    +  after 6 tries: stop and warn "thrashing"
    +

    That is not a prompt. That is a design. Every line is one of the five decisions I'd been making at 2am, implicitly, badly. Two of them are load-bearing. ask me before migrations or pushes is the line that lets me actually walk away — I'm not letting an unattended loop run a schema change while I sleep. And after 6 tries: stop and warn "thrashing" is the one I always dropped when I was the loop, because the worst loops are the ones that never admit they're stuck. That line is my dwindling patience, written down, so the run doesn't depend on my patience.

    +

    It fixed the bug. That wasn't the part that mattered. The part that mattered was that the five decisions were mine again, and I could see them.

    +

    The layering you already do by hand

    +

    Watch how you actually finish real work. You don't one-shot it. You get it working, then you fix the security thing you noticed on the way, then you refactor the ugly part, then you fix the UI the refactor knocked loose. You do that in sequence, by hand, re-establishing context at each handoff — and you drop the security pass the one time Slack pings mid-thought.

    +

    That sequence isn't overhead around the work. It is the work. So write it as the work — a pipeline, each story a stage:

    +
    pipeline "epic: checkout v2":
    +  stage "story: cart totals":
    +    goal: cart shows correct totals with tax
    +    done when "pnpm test cart" passes
    +    each cycle: plan, then act, then observe
    +    when it fails: reflect, then plan again
    +  stage "story: checkout submit":
    +    goal: order submits and payment is captured
    +    a human approves before charging the card
    +    done when "pnpm test checkout" passes
    +

    Stare at a human approves before charging the card. That's the most senior decision in the whole file, and it cost five words to make real and durable — not a Slack reminder, not a hope, a gate written into the structure exactly where the money moves. That's the job. That was always the job: deciding where judgment lives.

    +

    The loop is the craft now

    +

    Here's the thesis I backed into, against my own nostalgia. A flow you'd trust and a sloppy one-shot aren't separated by a smarter model or a cleverer prompt. They're separated by whether there's a loop: self-correcting, verified, gated, with an honest stop. The anatomy — plan, act, observe, and on failure reflect and re-plan — is what turns a lucky guess into something you'd ship. Bury that anatomy in a wall of prose and you're back to being the human for-loop at 2am.

    +

    So the loop isn't the packaging around the craft. The loop is the craft now. It's the part only judgment can author.

    +

    The thing I built, briefly

    +

    I made the loop a thing you write down. It's called Loop — a small open-source language, about fifteen words, plain English. Every snippet above is real syntax. You write a .loop file and it runs on Claude Code: it plans, acts, observes, reflects on failure, checks your done when, and stops at your gates. That's the whole idea.

    +

    I won't oversell the replacement. It's not identical to the 11pm flow of a function arriving under your hands, and some nights I still miss that one, honestly. But it gives back the part I actually missed — being the author — and it does it for work I'd never hand to a one-shot.

    +

    If any of the 2am stuff sounded familiar, try your next task as a loop instead of a prompt. Worst case, you spend ten minutes naming the five decisions you were already making anyway.

    + +
    \ No newline at end of file diff --git a/docs/blog/index.html b/docs/blog/index.html index 5f1ea5c..ad69fcf 100644 --- a/docs/blog/index.html +++ b/docs/blog/index.html @@ -35,5 +35,6 @@

    LoopFlow blog

    What is an AI coding loop?

    A self-correcting AI agent that plans, acts, and re-runs a real verification check until the proof is green — not a one-shot prompt you have to babysit.

    How to make Claude Code self-correct

    Claude Code does one pass and stops; a .loop gives it a verifiable finish line and a reflect back-edge so it retries until the tests actually pass.

    +

    I Was the For-Loop

    I thought I missed writing code. Turns out I missed deciding — and that part you can get back.

    \ No newline at end of file diff --git a/docs/sitemap.xml b/docs/sitemap.xml index 0bce932..b18f830 100644 --- a/docs/sitemap.xml +++ b/docs/sitemap.xml @@ -34,4 +34,5 @@ https://loopflow.live/blog/what-is-an-ai-coding-loop.html https://loopflow.live/blog/make-claude-code-self-correct.html https://loopflow.live/blog/one-shot-prompts-vs-self-correcting-loops.html + https://loopflow.live/blog/i-was-the-for-loop.html From 4940731463ebcfc45fb4d608f055dc0c41f62d31 Mon Sep 17 00:00:00 2001 From: tickets-forge-dev Date: Sun, 5 Jul 2026 01:06:30 -0400 Subject: [PATCH 9/9] seo(geo): SoftwareApplication + breadcrumb schema, RSS feed, IndexNow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Deeper AI-search / structured-data coverage: - homepage: add SoftwareApplication JSON-LD (entity signal — LoopFlow as a developer tool, free/Apache-2.0) alongside the existing WebSite + FAQPage - blog: add BreadcrumbList schema to all 4 posts; add blog/rss.xml + it - IndexNow: add key file + docs/tools/indexnow.sh to push all sitemap URLs to Bing (which powers ChatGPT search) for near-instant indexing post-deploy 39 JSON-LD blocks site-wide, all valid. Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/blog/i-was-the-for-loop.html | 2 ++ docs/blog/index.html | 1 + docs/blog/make-claude-code-self-correct.html | 2 ++ ...shot-prompts-vs-self-correcting-loops.html | 2 ++ docs/blog/rss.xml | 30 +++++++++++++++++++ docs/blog/what-is-an-ai-coding-loop.html | 2 ++ docs/fcd38f2db8c9466c9f122de285feaaa7.txt | 1 + docs/index.html | 3 ++ docs/tools/indexnow.sh | 16 ++++++++++ 9 files changed, 59 insertions(+) create mode 100644 docs/blog/rss.xml create mode 100644 docs/fcd38f2db8c9466c9f122de285feaaa7.txt create mode 100755 docs/tools/indexnow.sh diff --git a/docs/blog/i-was-the-for-loop.html b/docs/blog/i-was-the-for-loop.html index d442df5..e403f56 100644 --- a/docs/blog/i-was-the-for-loop.html +++ b/docs/blog/i-was-the-for-loop.html @@ -18,8 +18,10 @@ + +
    LoopFlow
    diff --git a/docs/blog/index.html b/docs/blog/index.html index ad69fcf..96c4ec5 100644 --- a/docs/blog/index.html +++ b/docs/blog/index.html @@ -18,6 +18,7 @@ + diff --git a/docs/blog/make-claude-code-self-correct.html b/docs/blog/make-claude-code-self-correct.html index a962825..537193c 100644 --- a/docs/blog/make-claude-code-self-correct.html +++ b/docs/blog/make-claude-code-self-correct.html @@ -18,8 +18,10 @@ + +
    LoopFlow
    diff --git a/docs/blog/one-shot-prompts-vs-self-correcting-loops.html b/docs/blog/one-shot-prompts-vs-self-correcting-loops.html index c958a66..1f88c0a 100644 --- a/docs/blog/one-shot-prompts-vs-self-correcting-loops.html +++ b/docs/blog/one-shot-prompts-vs-self-correcting-loops.html @@ -18,8 +18,10 @@ + +
    LoopFlow
    diff --git a/docs/blog/rss.xml b/docs/blog/rss.xml new file mode 100644 index 0000000..f1ce320 --- /dev/null +++ b/docs/blog/rss.xml @@ -0,0 +1,30 @@ + + + LoopFlow blog + https://loopflow.live/blog/ + Guides on self-correcting AI coding loops, AI agents, and loop engineering. + + What is an AI coding loop? + https://loopflow.live/blog/what-is-an-ai-coding-loop.html + https://loopflow.live/blog/what-is-an-ai-coding-loop.html + An AI coding loop is a self-correcting agent workflow that plans, acts, and verifies against a real check until it passes. + + + How to make Claude Code self-correct + https://loopflow.live/blog/make-claude-code-self-correct.html + https://loopflow.live/blog/make-claude-code-self-correct.html + Make Claude Code self-correct and retry until tests pass with a plain-English .loop file. + + + One-shot prompts vs self-correcting loops + https://loopflow.live/blog/one-shot-prompts-vs-self-correcting-loops.html + https://loopflow.live/blog/one-shot-prompts-vs-self-correcting-loops.html + Why a one-shot prompt stops whether or not it worked, and what a self-correcting loop adds. + + + I Was the For-Loop + https://loopflow.live/blog/i-was-the-for-loop.html + https://loopflow.live/blog/i-was-the-for-loop.html + A personal essay on what changed when AI started writing the code: the five decisions behind every task. + + diff --git a/docs/blog/what-is-an-ai-coding-loop.html b/docs/blog/what-is-an-ai-coding-loop.html index 4c5d541..0443d3d 100644 --- a/docs/blog/what-is-an-ai-coding-loop.html +++ b/docs/blog/what-is-an-ai-coding-loop.html @@ -18,8 +18,10 @@ + +
    LoopFlow
    diff --git a/docs/fcd38f2db8c9466c9f122de285feaaa7.txt b/docs/fcd38f2db8c9466c9f122de285feaaa7.txt new file mode 100644 index 0000000..e0ce9cd --- /dev/null +++ b/docs/fcd38f2db8c9466c9f122de285feaaa7.txt @@ -0,0 +1 @@ +fcd38f2db8c9466c9f122de285feaaa7 \ No newline at end of file diff --git a/docs/index.html b/docs/index.html index 7d5fe84..b318c5c 100644 --- a/docs/index.html +++ b/docs/index.html @@ -22,6 +22,9 @@ + diff --git a/docs/tools/indexnow.sh b/docs/tools/indexnow.sh new file mode 100755 index 0000000..97ab40d --- /dev/null +++ b/docs/tools/indexnow.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +# Notify IndexNow (Bing / ChatGPT-search, Yandex) of all loopflow.live URLs. +# Run AFTER deploying, and again whenever pages change. Reads docs/sitemap.xml. +set -euo pipefail +KEY="fcd38f2db8c9466c9f122de285feaaa7" +HOST="loopflow.live" +DOCS="$(cd "$(dirname "$0")/.." && pwd)" +URLS=$(grep -oE '[^<]+' "$DOCS/sitemap.xml" | sed 's///') +JSON=$(printf '%s\n' "$URLS" | python3 -c ' +import sys,json +urls=[l.strip() for l in sys.stdin if l.strip()] +print(json.dumps({"host":"loopflow.live","key":"'"$KEY"'","keyLocation":"https://loopflow.live/'"$KEY"'.txt","urlList":urls}))') +echo "Submitting $(printf '%s\n' "$URLS" | wc -l | tr -d ' ') URLs to IndexNow..." +curl -sS -X POST "https://api.indexnow.org/indexnow" \ + -H "Content-Type: application/json; charset=utf-8" \ + -d "$JSON" -w "\nHTTP %{http_code}\n"