Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
e8d9f71
Make check.mjs line-ending robust and pin LF via .gitattributes
justkidding2047 Sep 2, 2026
321bf5a
Fix config and documentation truthfulness
justkidding2047 Sep 2, 2026
9796181
worker: rate-limit votes, UTC feed timestamps, drop dead helpers, wid…
justkidding2047 Sep 2, 2026
bcd367e
test(worker): cover daily caps, weekly hourly cap, and origin-suffix …
justkidding2047 Sep 2, 2026
f52f3b6
Test LoopCatalog and VoteStore Durable Objects against real SQLite
justkidding2047 Sep 2, 2026
3cec5f4
Self-host Inter and IBM Plex Mono with font-display: swap
justkidding2047 Sep 2, 2026
42c0741
Fix homepage first-paint sort, vote a11y labels, twitter meta, and fo…
justkidding2047 Sep 2, 2026
c476e4c
gauntlet: merge P1 CRLF-safe gate
justkidding2047 Sep 2, 2026
35233c7
gauntlet: merge P7 worker hygiene
justkidding2047 Sep 2, 2026
4cbd4d6
check.mjs: gate self-hosted font files, preloads, swap, licenses
justkidding2047 Sep 2, 2026
441d8e2
gauntlet: merge P5 rate-limit tests
justkidding2047 Sep 2, 2026
b76b90f
feat(worker): enforce minimum form completion time server-side
justkidding2047 Sep 2, 2026
6ee40f6
Close gate-suite holes: alias readdir mirror, audit.md gate, example …
justkidding2047 Sep 2, 2026
b937dbf
Gate README, audit, and CHANGELOG truthfulness fixes in check.mjs
justkidding2047 Sep 2, 2026
b50ea8f
worker: make public rendered surfaces cacheable for 60s
justkidding2047 Sep 2, 2026
195d7ad
gauntlet: merge P3 config/docs truth (resolve check.mjs readText)
justkidding2047 Sep 2, 2026
d6b197d
gauntlet: merge P2
justkidding2047 Sep 2, 2026
6fc41c0
gauntlet: merge P4
justkidding2047 Sep 2, 2026
6d1cf4e
gauntlet: merge P6
justkidding2047 Sep 2, 2026
cd3e945
P10 round 2: label-in-name copy button, gate pins for a11y/twitter/fa…
justkidding2047 Sep 2, 2026
1e00c36
Repair Loopy terminal-state vocabulary, publish untrusted clause, Not…
justkidding2047 Sep 2, 2026
dc604e1
gauntlet: merge P10 site a11y/stability
justkidding2047 Sep 2, 2026
ef4dd1e
worker: keep 404s and shell headers out of the public cache
justkidding2047 Sep 2, 2026
c7f7daf
fonts: cover U+2190-2193 in Inter subset; trim OFL trailing space
justkidding2047 Sep 2, 2026
6455c14
gauntlet: merge P12 self-hosted fonts
justkidding2047 Sep 2, 2026
31c6419
gauntlet: merge P11 cacheable public HTML
justkidding2047 Sep 2, 2026
a871441
Mirror vocabulary fix into loop-library alias SKILL.md; gate it in ch…
justkidding2047 Sep 2, 2026
b9d156c
gauntlet: merge P8 skill terminal-state vocabulary
justkidding2047 Sep 2, 2026
c6ffac3
Route Loopy to Find first and de-triplicate the loop design rules
justkidding2047 Sep 2, 2026
67044fa
gauntlet: merge P9 skill routing and de-triplication
justkidding2047 Sep 2, 2026
a2f3b41
P13: bump script.js cache token, pin renderer token to shell, dedupe …
justkidding2047 Sep 2, 2026
2c6d2d7
gauntlet: merge P13 review fixes (script cache token, docs, no-store …
justkidding2047 Sep 2, 2026
35e8ac7
loopy: bind fanned-out pieces to the stated outcome before starting a…
justkidding2047 Sep 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* text=auto eol=lf
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ jobs:
python3 -m json.tool loop-library/site/.herenow/data.json >/dev/null
python3 -m json.tool loop-library/site/.herenow/proxy.json >/dev/null
python3 -m json.tool loop-library/scripts/seo-geo-query-benchmark.json >/dev/null
git diff --check
git diff --check $(git hash-object -t tree /dev/null) HEAD

- name: Test form Worker
run: npm --prefix loop-library/worker run check
13 changes: 10 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ this repository layout.
- Every loop must have a stable slug, unique number, search title and
description, contributor attribution, published and modified dates,
practical context, verification criteria, category, keywords, and valid
related-loop slugs.
related-loop slugs. `categoryLabel` must match the label that
`loop-library/worker/src/loop-schema.js` maps for the record's `category`,
because the page chip uses the mapping while structured data uses the field.
- Do not hand-edit the homepage, detail pages, catalogs, feed, sitemap, or
Loopy skill content when publishing a database record. The Worker renders
those public surfaces from the same record. New loops use the shared social card unless a
Expand All @@ -55,12 +57,14 @@ this repository layout.
python3 -m json.tool loop-library/site/.herenow/data.json >/dev/null
python3 -m json.tool loop-library/site/.herenow/proxy.json >/dev/null
python3 -m json.tool loop-library/scripts/seo-geo-query-benchmark.json >/dev/null
git diff --check
git diff --check $(git hash-object -t tree /dev/null) HEAD
```

- Do not publish a loop unless its public homepage row, detail page,
`catalog.json`, `catalog.md`, `catalog.txt`, `llms.txt`, sitemap, and feed
all read back from production with the expected slug and modified date.
Read back with a cache-busting query string; without it a cached copy can be
served for up to a minute and one stale copy for up to ten.

## Protected forms

Expand All @@ -71,7 +75,8 @@ this repository layout.
credentials or allow direct public inserts.
- Keep Turnstile validation for the expected action, hostname, and origin, plus
the existing schema checks, rate limits, duplicate suppression, honeypot,
minimum completion time, and idempotency handling.
minimum completion time (1200 ms for loop suggestions, 800 ms for weekly
signups, enforced in the Worker), and idempotency handling.
- Keep loop suggestions limited to 3/hour and 10/day per IP, and weekly signups
limited to 5/hour and 10/day per IP. Matching content or email submitted
within 24 hours should succeed without creating a second record.
Expand Down Expand Up @@ -124,6 +129,8 @@ npm run deploy
provider ID, username, and voter key exclusively from that verified token.
Reject explicit untrusted Origins; missing Origins are expected through the
here.now proxy and remain protected by the required bearer token.
- Vote writes are rate limited per signed-in account through the shared
`TURNSTILE_RATE_LIMITER` binding (30 per minute, per `wrangler.jsonc`).
- Do not expose OAuth client secrets or `SESSION_SECRET` in Worker variables,
browser code, logs, or committed development files. Configure them with:

Expand Down
49 changes: 49 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,54 @@
# Changelog

## 2026-09-02

### Added

- Enforced the minimum form completion time in the Worker: submissions
without a plausible `form_elapsed_ms` receive the silent 202 instead of a
record.
- Rate limited vote writes per signed-in account through the shared
`TURNSTILE_RATE_LIMITER` binding, returning the same 429 shape as the forms.
- Tested the `LoopCatalog` and `VoteStore` Durable Objects against real
SQLite instead of stubs.
- Self-hosted Inter and IBM Plex Mono with `font-display: swap`, preloads,
and OFL licenses alongside.

### Changed

- Rendered public pages, catalogs, feed, and sitemap now carry a public
`max-age=60, stale-while-revalidate=600` cache header; 404s, shell errors,
admin, session, and vote routes stay `no-store`.
- Atom feed `<published>` and `<updated>` timestamps are emitted in UTC.
- Hardened the gate suite: `check.mjs` is CRLF-safe with LF pinned in
`.gitattributes`, mirrors every `skills/loopy/references` file into the
`skills/loop-library` alias, and `git diff --check` runs repo-wide.
- Repaired the Loopy skill's terminal-state vocabulary, added the `Not
ready` Loop Doctor verdict, and routed the default prompt to Find a
published loop before crafting one.

## 2026-07-07

### Added

- Added a dedicated "Most popular" sort option to the Loop Library homepage
sort dropdown, ordering loops by vote count.
- Served a branded fallback homepage from the Worker's own catalog when the
here.now shell fetch fails or returns a 5xx. The page keeps the site chrome,
lists every published loop, points agents at `catalog.json` and `llms.txt`,
preserves the upstream failure status, and is marked `noindex`.
- Documented the redirect-only Vercel project in
`infra/signals-forwardfuture-ai-redirect/` that permanently redirects the
legacy `https://signals.forwardfuture.ai/*` host to
`https://signals.forwardfuture.com/*`.

### Changed

- Hardened the harness checks: `check.mjs` now asserts that README.md,
AGENTS.md, and the CI workflow all list the same validation commands, the
publish read-back checklist includes `catalog.txt` and `llms.txt`, and the
vote route returns an unavailable response when `VOTE_STORE` is not bound.

## 2026-07-03

### Added
Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Loop Library has two separate but related parts in this repository:

| Part | What it is | Where it lives |
| --- | --- | --- |
| **Loop Library website** | The public catalog where people and agents can browse published loops, read them, and copy their prompts. No installation is required. | [Live website](https://signals.forwardfuture.com/loop-library/) · all website code under [`loop-library/`](loop-library/) (shell in [`loop-library/site/`](loop-library/site/), database and rendering in [`loop-library/worker/`](loop-library/worker/)) |
| **Loop Library website** | The public catalog where people and agents can browse published loops, read them, and copy their prompts. No installation is required. | [Live website](https://signals.forwardfuture.com/loop-library/) · all website code under [`loop-library/`](loop-library/) (shell in [`loop-library/site/`](loop-library/site/), database and rendering in [`loop-library/worker/`](loop-library/worker/), gate script in [`loop-library/scripts/`](loop-library/scripts/), audits in [`loop-library/audits/`](loop-library/audits/)) |
| **Loopy skill** | An optional installable guide that helps an AI agent discover, find, audit, repair, craft, run, debrief, save, or prepare loops for publication. It uses the website's live catalog when recommending or publishing loops. | source in [`skills/loopy/`](skills/loopy/) |

The website is the library; Loopy is a companion way to work with it. You
Expand Down Expand Up @@ -297,9 +297,9 @@ LOOP_PUBLISH_TOKEN=... \
```

The command validates the record and publishes the homepage row, detail page,
JSON/Markdown/plain-text catalogs, feed, and sitemap from the same database
write. Use `--draft` to save a non-public record or `--archive` to remove a
record from public responses without deleting its revision history.
JSON/Markdown/plain-text catalogs, `llms.txt`, feed, and sitemap from the same
database write. Use `--draft` to save a non-public record or `--archive` to
remove a record from public responses without deleting its revision history.

The first database-backed release needs one import from the private migration
bundle. Loop records and bootstrap data are intentionally not committed to
Expand Down Expand Up @@ -357,7 +357,7 @@ npm --prefix loop-library/worker run check
python3 -m json.tool loop-library/site/.herenow/data.json >/dev/null
python3 -m json.tool loop-library/site/.herenow/proxy.json >/dev/null
python3 -m json.tool loop-library/scripts/seo-geo-query-benchmark.json >/dev/null
git diff --check
git diff --check $(git hash-object -t tree /dev/null) HEAD
```

### Configure voting
Expand Down
5 changes: 4 additions & 1 deletion loop-library/audits/seo-geo-2026-06-19.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,10 @@ query.
crawlers and the sitemap is live and linked from every page. Add the sitemap
at the root-domain owner when that configuration is next changed.

## Current stop state
## Stop state as of 2026-06-19

The catalog had 30 canonical pages when this snapshot was captured; later
loops are not covered by these numbers.

The local crawl has no critical, high, or medium technical/content findings,
and all 33 priority intents map to an answer-ready page. The external benchmark
Expand Down
Loading