diff --git a/scripts/build-loop-pages.mjs b/scripts/build-loop-pages.mjs
index 27078ad..488a391 100644
--- a/scripts/build-loop-pages.mjs
+++ b/scripts/build-loop-pages.mjs
@@ -252,7 +252,7 @@ function renderLoopPage(loop) {
-
+
${escapeHtml(loop.seoTitle)}
diff --git a/scripts/check.mjs b/scripts/check.mjs
index d949490..196847e 100644
--- a/scripts/check.mjs
+++ b/scripts/check.mjs
@@ -544,7 +544,7 @@ for (const [index, loop] of loops.entries()) {
);
assert(page.includes(`rel="help" href="${siteMeta.baseUrl}agents/"`));
assert(page.includes("../../styles.css?v=20260620-primary-nav"));
- assert(page.includes("../../script.js?v=20260620-primary-nav"));
+ assert(page.includes("../../script.js?v=20260621-retry-after"));
assert(page.includes(`Type'));
assert(html.includes("./styles.css?v=20260620-primary-nav"));
-assert(html.includes("./script.js?v=20260620-primary-nav"));
+assert(html.includes("./script.js?v=20260621-retry-after"));
const homepagePostText =
"Find Loops and create your own - Loop Library";
assert(html.includes('class="share-actions" aria-label="Share Loop Library"'));
@@ -870,7 +870,7 @@ assert.equal(
2,
);
assert(learnHtml.includes("../styles.css?v=20260620-article-layout"));
-assert(learnHtml.includes("../script.js?v=20260620-primary-nav"));
+assert(learnHtml.includes("../script.js?v=20260621-retry-after"));
assert(learnHtml.includes("How agent loops work"));
assert(learnHtml.includes('
-
+
-
+
Loop Library: Repeatable AI Agent Workflows | Forward Future
diff --git a/site/learn/index.html b/site/learn/index.html
index 813854f..171120f 100644
--- a/site/learn/index.html
+++ b/site/learn/index.html
@@ -75,7 +75,7 @@
/>
-
+
-
+
100% Test Coverage Loop for Coding Agents | Loop Library
diff --git a/site/loops/accessibility-repair-loop/index.html b/site/loops/accessibility-repair-loop/index.html
index 480230b..8b00db8 100644
--- a/site/loops/accessibility-repair-loop/index.html
+++ b/site/loops/accessibility-repair-loop/index.html
@@ -132,7 +132,7 @@
]
}
-
+
Accessibility Repair Loop | Loop Library
diff --git a/site/loops/architecture-satisfaction-loop/index.html b/site/loops/architecture-satisfaction-loop/index.html
index 6196a03..f1f007c 100644
--- a/site/loops/architecture-satisfaction-loop/index.html
+++ b/site/loops/architecture-satisfaction-loop/index.html
@@ -132,7 +132,7 @@
]
}
-
+
Architecture Refactoring Loop for Coding Agents | Loop Library
diff --git a/site/loops/autonomy-loop/index.html b/site/loops/autonomy-loop/index.html
index 095ab9e..8c356d3 100644
--- a/site/loops/autonomy-loop/index.html
+++ b/site/loops/autonomy-loop/index.html
@@ -133,7 +133,7 @@
]
}
-
+
autonomy-loop Builder-Reviewer Workflow | Loop Library
diff --git a/site/loops/axelrod-subagent-arena-loop/index.html b/site/loops/axelrod-subagent-arena-loop/index.html
index a5eb0d7..19a76c6 100644
--- a/site/loops/axelrod-subagent-arena-loop/index.html
+++ b/site/loops/axelrod-subagent-arena-loop/index.html
@@ -133,7 +133,7 @@
]
}
-
+
Axelrod Subagent Arena Benchmark | Loop Library
diff --git a/site/loops/boeing-747-benchmark/index.html b/site/loops/boeing-747-benchmark/index.html
index b422ff0..3b1bf96 100644
--- a/site/loops/boeing-747-benchmark/index.html
+++ b/site/loops/boeing-747-benchmark/index.html
@@ -133,7 +133,7 @@
]
}
-
+
Boeing 747 Three.js Vision Benchmark | Loop Library
diff --git a/site/loops/clodex-adversarial-review-loop/index.html b/site/loops/clodex-adversarial-review-loop/index.html
index 390a505..8f25ed1 100644
--- a/site/loops/clodex-adversarial-review-loop/index.html
+++ b/site/loops/clodex-adversarial-review-loop/index.html
@@ -133,7 +133,7 @@
]
}
-
+
Clodex Adversarial Code Review Loop | Loop Library
diff --git a/site/loops/codex-completion-contract-loop/index.html b/site/loops/codex-completion-contract-loop/index.html
index ae8c50a..d73f524 100644
--- a/site/loops/codex-completion-contract-loop/index.html
+++ b/site/loops/codex-completion-contract-loop/index.html
@@ -133,7 +133,7 @@
]
}
-
+
Codex Completion Contract and Evidence Loop | Loop Library
diff --git a/site/loops/cold-load-trimmer-loop/index.html b/site/loops/cold-load-trimmer-loop/index.html
index 441523e..92971af 100644
--- a/site/loops/cold-load-trimmer-loop/index.html
+++ b/site/loops/cold-load-trimmer-loop/index.html
@@ -133,7 +133,7 @@
]
}
-
+
Cold-Load Byte Reduction Loop | Loop Library
diff --git a/site/loops/customer-ai-deployment-loop/index.html b/site/loops/customer-ai-deployment-loop/index.html
index 725d6e4..b353d7d 100644
--- a/site/loops/customer-ai-deployment-loop/index.html
+++ b/site/loops/customer-ai-deployment-loop/index.html
@@ -133,7 +133,7 @@
]
}
-
+
Customer AI Deployment Loop | Loop Library
diff --git a/site/loops/devils-advocate-design-loop/index.html b/site/loops/devils-advocate-design-loop/index.html
index 689476c..d7ba578 100644
--- a/site/loops/devils-advocate-design-loop/index.html
+++ b/site/loops/devils-advocate-design-loop/index.html
@@ -132,7 +132,7 @@
]
}
-
+
Devil's-Advocate Design Review Loop | Loop Library
diff --git a/site/loops/easy-onboarding-loop/index.html b/site/loops/easy-onboarding-loop/index.html
index f735ab2..6536244 100644
--- a/site/loops/easy-onboarding-loop/index.html
+++ b/site/loops/easy-onboarding-loop/index.html
@@ -132,7 +132,7 @@
]
}
-
+
Fresh-State Onboarding Improvement Loop | Loop Library
diff --git a/site/loops/exhaustive-logging-coverage-loop/index.html b/site/loops/exhaustive-logging-coverage-loop/index.html
index 71b4b53..cbe51fc 100644
--- a/site/loops/exhaustive-logging-coverage-loop/index.html
+++ b/site/loops/exhaustive-logging-coverage-loop/index.html
@@ -132,7 +132,7 @@
]
}
-
+
Logging Coverage Loop for Coding Agents | Loop Library
diff --git a/site/loops/five-minute-repository-maintainer-loop/index.html b/site/loops/five-minute-repository-maintainer-loop/index.html
index 2ab9e1d..f53fab4 100644
--- a/site/loops/five-minute-repository-maintainer-loop/index.html
+++ b/site/loops/five-minute-repository-maintainer-loop/index.html
@@ -133,7 +133,7 @@
]
}
-
+
Five-Minute Repository Maintainer Loop | Loop Library
diff --git a/site/loops/fresh-clone-loop/index.html b/site/loops/fresh-clone-loop/index.html
index b008a7c..208c54f 100644
--- a/site/loops/fresh-clone-loop/index.html
+++ b/site/loops/fresh-clone-loop/index.html
@@ -132,7 +132,7 @@
]
}
-
+
Fresh Clone README Verification Loop | Loop Library
diff --git a/site/loops/full-product-evaluation-loop/index.html b/site/loops/full-product-evaluation-loop/index.html
index c9dbb18..ffeedbd 100644
--- a/site/loops/full-product-evaluation-loop/index.html
+++ b/site/loops/full-product-evaluation-loop/index.html
@@ -132,7 +132,7 @@
]
}
-
+
Full Product Evaluation Loop for AI Systems | Loop Library
diff --git a/site/loops/goal-forge-loop/index.html b/site/loops/goal-forge-loop/index.html
index 28d0453..46c76ae 100644
--- a/site/loops/goal-forge-loop/index.html
+++ b/site/loops/goal-forge-loop/index.html
@@ -133,7 +133,7 @@
]
}
-
+
Goal Forge Specification Loop for Codex | Loop Library
diff --git a/site/loops/housekeeper-loop/index.html b/site/loops/housekeeper-loop/index.html
index ca9048b..c537b33 100644
--- a/site/loops/housekeeper-loop/index.html
+++ b/site/loops/housekeeper-loop/index.html
@@ -132,7 +132,7 @@
]
}
-
+
Repository Housekeeper Cleanup Loop | Loop Library
diff --git a/site/loops/infinite-clickbait-loop/index.html b/site/loops/infinite-clickbait-loop/index.html
index 1e6835d..6767192 100644
--- a/site/loops/infinite-clickbait-loop/index.html
+++ b/site/loops/infinite-clickbait-loop/index.html
@@ -132,7 +132,7 @@
]
}
-
+
Infinite Clickbait Thumbnail Iteration Loop | Loop Library
diff --git a/site/loops/loop-harness-verification-loop/index.html b/site/loops/loop-harness-verification-loop/index.html
index c7b0e1e..4eabcce 100644
--- a/site/loops/loop-harness-verification-loop/index.html
+++ b/site/loops/loop-harness-verification-loop/index.html
@@ -133,7 +133,7 @@
]
}
-
+
Loop Harness Second-Agent Verification Workflow | Loop Library
diff --git a/site/loops/multi-llm-convergence-loop/index.html b/site/loops/multi-llm-convergence-loop/index.html
index 9038086..10fe9fe 100644
--- a/site/loops/multi-llm-convergence-loop/index.html
+++ b/site/loops/multi-llm-convergence-loop/index.html
@@ -133,7 +133,7 @@
]
}
-
+
Multi-LLM Convergence Review Loop | Loop Library
diff --git a/site/loops/nightly-changelog-sweep/index.html b/site/loops/nightly-changelog-sweep/index.html
index 3c8c174..7b98669 100644
--- a/site/loops/nightly-changelog-sweep/index.html
+++ b/site/loops/nightly-changelog-sweep/index.html
@@ -132,7 +132,7 @@
]
}
-
+
Nightly Changelog Loop for Coding Agents | Loop Library
diff --git a/site/loops/overnight-docs-sweep/index.html b/site/loops/overnight-docs-sweep/index.html
index 5338de2..d2dc30d 100644
--- a/site/loops/overnight-docs-sweep/index.html
+++ b/site/loops/overnight-docs-sweep/index.html
@@ -132,7 +132,7 @@
]
}
-
+
Documentation Sweep for Coding Agents | Loop Library
diff --git a/site/loops/pixel-safe-css-trim-loop/index.html b/site/loops/pixel-safe-css-trim-loop/index.html
index 564fc4d..52b284b 100644
--- a/site/loops/pixel-safe-css-trim-loop/index.html
+++ b/site/loops/pixel-safe-css-trim-loop/index.html
@@ -133,7 +133,7 @@
]
}
-
+
Pixel-Safe CSS Reduction Loop | Loop Library
diff --git a/site/loops/post-release-baseline-loop/index.html b/site/loops/post-release-baseline-loop/index.html
index bb9bcf9..46c756d 100644
--- a/site/loops/post-release-baseline-loop/index.html
+++ b/site/loops/post-release-baseline-loop/index.html
@@ -132,7 +132,7 @@
]
}
-
+
Post-Release Benchmark Baseline Loop | Loop Library
diff --git a/site/loops/prepare-new-project-loop/index.html b/site/loops/prepare-new-project-loop/index.html
index f2e55ac..ed3a027 100644
--- a/site/loops/prepare-new-project-loop/index.html
+++ b/site/loops/prepare-new-project-loop/index.html
@@ -132,7 +132,7 @@
]
}
-
+
Prepare a New Project Documentation Loop | Loop Library
diff --git a/site/loops/product-update-podcast-loop/index.html b/site/loops/product-update-podcast-loop/index.html
index 04b07fd..ca90745 100644
--- a/site/loops/product-update-podcast-loop/index.html
+++ b/site/loops/product-update-podcast-loop/index.html
@@ -133,7 +133,7 @@
]
}
-
+
Product Update Podcast Automation Loop | Loop Library
diff --git a/site/loops/production-data-cleanup-loop/index.html b/site/loops/production-data-cleanup-loop/index.html
index da4c5b9..7d40428 100644
--- a/site/loops/production-data-cleanup-loop/index.html
+++ b/site/loops/production-data-cleanup-loop/index.html
@@ -132,7 +132,7 @@
]
}
-
+
Production Data Cleanup Loop for AI Systems | Loop Library
diff --git a/site/loops/production-error-sweep/index.html b/site/loops/production-error-sweep/index.html
index c079cfd..8d2e228 100644
--- a/site/loops/production-error-sweep/index.html
+++ b/site/loops/production-error-sweep/index.html
@@ -132,7 +132,7 @@
]
}
-
+
Production Error Triage Loop for Coding Agents | Loop Library
diff --git a/site/loops/promise-to-proof-loop/index.html b/site/loops/promise-to-proof-loop/index.html
index 7ae61c3..ceb3d55 100644
--- a/site/loops/promise-to-proof-loop/index.html
+++ b/site/loops/promise-to-proof-loop/index.html
@@ -132,7 +132,7 @@
]
}
-
+
Promise-to-Proof Product Audit | Loop Library
diff --git a/site/loops/propagation-compliance-loop/index.html b/site/loops/propagation-compliance-loop/index.html
index ac1f400..9b2b33a 100644
--- a/site/loops/propagation-compliance-loop/index.html
+++ b/site/loops/propagation-compliance-loop/index.html
@@ -132,7 +132,7 @@
]
}
-
+
Repository Propagation Compliance Loop | Loop Library
diff --git a/site/loops/quality-streak-loop/index.html b/site/loops/quality-streak-loop/index.html
index cb4fd06..e7e802d 100644
--- a/site/loops/quality-streak-loop/index.html
+++ b/site/loops/quality-streak-loop/index.html
@@ -132,7 +132,7 @@
]
}
-
+
Quality Streak Evaluation Loop for AI Products | Loop Library
diff --git a/site/loops/recent-feedback-sweep/index.html b/site/loops/recent-feedback-sweep/index.html
index 08323aa..8f7525f 100644
--- a/site/loops/recent-feedback-sweep/index.html
+++ b/site/loops/recent-feedback-sweep/index.html
@@ -132,7 +132,7 @@
]
}
-
+
Recent-Feedback Project Audit | Loop Library
diff --git a/site/loops/repository-cleanup-loop/index.html b/site/loops/repository-cleanup-loop/index.html
index fd20151..65bebb5 100644
--- a/site/loops/repository-cleanup-loop/index.html
+++ b/site/loops/repository-cleanup-loop/index.html
@@ -132,7 +132,7 @@
]
}
-
+
Repository Cleanup Loop for Coding Agents | Loop Library
diff --git a/site/loops/revolve-self-improvement-loop/index.html b/site/loops/revolve-self-improvement-loop/index.html
index edd8428..7669f23 100644
--- a/site/loops/revolve-self-improvement-loop/index.html
+++ b/site/loops/revolve-self-improvement-loop/index.html
@@ -133,7 +133,7 @@
]
}
-
+
Revolve Versioned Experiment Loop | Loop Library
diff --git a/site/loops/self-improving-champion-loop/index.html b/site/loops/self-improving-champion-loop/index.html
index 0929f01..ef93040 100644
--- a/site/loops/self-improving-champion-loop/index.html
+++ b/site/loops/self-improving-champion-loop/index.html
@@ -132,7 +132,7 @@
]
}
-
+
Self-Improving Champion Evaluation Loop | Loop Library
diff --git a/site/loops/seo-geo-visibility-loop/index.html b/site/loops/seo-geo-visibility-loop/index.html
index 6104f51..e6a33bf 100644
--- a/site/loops/seo-geo-visibility-loop/index.html
+++ b/site/loops/seo-geo-visibility-loop/index.html
@@ -132,7 +132,7 @@
]
}
-
+
SEO and GEO Visibility Audit Loop | Loop Library
diff --git a/site/loops/stale-safe-batch-release-loop/index.html b/site/loops/stale-safe-batch-release-loop/index.html
index 613d241..78abe8d 100644
--- a/site/loops/stale-safe-batch-release-loop/index.html
+++ b/site/loops/stale-safe-batch-release-loop/index.html
@@ -132,7 +132,7 @@
]
}
-
+
Stale-Safe Batch Release Loop | Loop Library
diff --git a/site/loops/sub-50ms-page-load-loop/index.html b/site/loops/sub-50ms-page-load-loop/index.html
index 299feca..dbca03e 100644
--- a/site/loops/sub-50ms-page-load-loop/index.html
+++ b/site/loops/sub-50ms-page-load-loop/index.html
@@ -132,7 +132,7 @@
]
}
-
+
Sub-50 ms Page-Load Optimization Loop | Loop Library
diff --git a/site/loops/test-stabilizer-loop/index.html b/site/loops/test-stabilizer-loop/index.html
index af1123e..2d81e13 100644
--- a/site/loops/test-stabilizer-loop/index.html
+++ b/site/loops/test-stabilizer-loop/index.html
@@ -132,7 +132,7 @@
]
}
-
+
Flaky Test Stabilizer Loop | Loop Library
diff --git a/site/loops/test-suite-speed-loop/index.html b/site/loops/test-suite-speed-loop/index.html
index c524eb0..f0cb802 100644
--- a/site/loops/test-suite-speed-loop/index.html
+++ b/site/loops/test-suite-speed-loop/index.html
@@ -132,7 +132,7 @@
]
}
-
+
Test-Suite Speed Optimization Loop | Loop Library
diff --git a/site/loops/ticket-to-pr-ready-loop/index.html b/site/loops/ticket-to-pr-ready-loop/index.html
index 1e34821..2b7b6f8 100644
--- a/site/loops/ticket-to-pr-ready-loop/index.html
+++ b/site/loops/ticket-to-pr-ready-loop/index.html
@@ -133,7 +133,7 @@
]
}
-
+
Ticket-to-PR-Ready Loop for Coding Agents | Loop Library
diff --git a/site/loops/ui-ux-score-loop/index.html b/site/loops/ui-ux-score-loop/index.html
index 6952466..dca5da3 100644
--- a/site/loops/ui-ux-score-loop/index.html
+++ b/site/loops/ui-ux-score-loop/index.html
@@ -133,7 +133,7 @@
]
}
-
+
Browser UI/UX Score Loop | Loop Library
diff --git a/site/loops/war-loops-frontend-designer/index.html b/site/loops/war-loops-frontend-designer/index.html
index 861af2e..aec14f8 100644
--- a/site/loops/war-loops-frontend-designer/index.html
+++ b/site/loops/war-loops-frontend-designer/index.html
@@ -133,7 +133,7 @@
]
}
-
+
War Loops Frontend Reconstruction Workflow | Loop Library
diff --git a/site/script.js b/site/script.js
index cca734f..62bbc40 100644
--- a/site/script.js
+++ b/site/script.js
@@ -656,6 +656,20 @@ async function initializeFormProtection() {
}
}
+function formatRetryHint(seconds) {
+ if (!Number.isFinite(seconds) || seconds <= 0) {
+ return "";
+ }
+
+ if (seconds < 90) {
+ const rounded = Math.max(1, Math.ceil(seconds));
+ return ` Try again in about ${rounded} second${rounded === 1 ? "" : "s"}.`;
+ }
+
+ const minutes = Math.max(1, Math.ceil(seconds / 60));
+ return ` Try again in about ${minutes} minute${minutes === 1 ? "" : "s"}.`;
+}
+
async function postProtectedForm(path, body, fallbackMessage) {
const response = await fetch(`${FORM_API_ORIGIN}${path}`, {
method: "POST",
@@ -674,9 +688,13 @@ async function postProtectedForm(path, body, fallbackMessage) {
}
if (!response.ok) {
- throw new Error(
- responseBody.error || fallbackMessage,
- );
+ let message = responseBody.error || fallbackMessage;
+
+ if (response.status === 429) {
+ message += formatRetryHint(Number(response.headers.get("Retry-After")));
+ }
+
+ throw new Error(message);
}
}
diff --git a/worker/src/index.js b/worker/src/index.js
index 401fdfa..8d8940c 100644
--- a/worker/src/index.js
+++ b/worker/src/index.js
@@ -314,6 +314,7 @@ function getCorsHeaders(origin, env) {
return {
"Access-Control-Allow-Origin": origin,
+ "Access-Control-Expose-Headers": "Retry-After",
"Cache-Control": "no-store",
Vary: "Origin",
};
diff --git a/worker/test/index.test.js b/worker/test/index.test.js
index 6a6b882..02cf59d 100644
--- a/worker/test/index.test.js
+++ b/worker/test/index.test.js
@@ -342,6 +342,10 @@ test("rate limits invalid-token floods before calling Siteverify", async () => {
assert.equal(response.status, 429);
assert.equal(response.headers.get("Retry-After"), "60");
+ assert.equal(
+ response.headers.get("Access-Control-Expose-Headers"),
+ "Retry-After",
+ );
assert.equal(body.code, "rate_limited");
assert.deepEqual(rateLimitCalls, ["suggestions:203.0.113.10"]);
assert.equal(calls.turnstile.length, 0);