{"id":51530692,"url":"https://github.com/acoyfellow/loop","last_synced_at":"2026-07-09T02:01:05.163Z","repository":{"id":360541321,"uuid":"1136921688","full_name":"acoyfellow/loop","owner":"acoyfellow","description":"prepare repos for looping.","archived":false,"fork":false,"pushed_at":"2026-05-26T20:41:43.000Z","size":320,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-26T22:16:38.692Z","etag":null,"topics":["ai","ai-agents","git","loops"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/acoyfellow.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-18T15:51:00.000Z","updated_at":"2026-05-26T20:41:47.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/acoyfellow/loop","commit_stats":null,"previous_names":["acoyfellow/loop"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/acoyfellow/loop","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acoyfellow%2Floop","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acoyfellow%2Floop/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acoyfellow%2Floop/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acoyfellow%2Floop/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/acoyfellow","download_url":"https://codeload.github.com/acoyfellow/loop/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acoyfellow%2Floop/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35283905,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-09T02:00:07.329Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","ai-agents","git","loops"],"created_at":"2026-07-09T02:01:03.434Z","updated_at":"2026-07-09T02:01:05.156Z","avatar_url":"https://github.com/acoyfellow.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# loop\n\nA personal chatbot that **ships working artifacts**. Every reply can compile a real Svelte 5 widget next to the conversation. The assistant also takes notes (\"remember that I prefer dark themes\") and they stick. One long-running session per account — older turns roll into searchable long-term memory; press **reset** to start over.\n\nLive: \u003chttps://loop.coey.dev\u003e · sign-up requires an invite password.\n\n![Six model-authored Svelte artifacts — Mandelbrot, orbits, spectrum, rain, sparkline, hex grid — running side by side in one loop session](https://loop.coey.dev/og-flex.png)\n\n*Six artifacts in one session: Mandelbrot fractal, orbital planets with trails, animated audio spectrum, Matrix-style katakana rain, scrolling stock sparkline, and a rippling hexagonal grid. Each one is real Svelte 5 — generated by Kimi-K2.6, compiled on the Worker, mounted in a sandboxed iframe.*\n\n```\nyou ──▶ chat session (Durable Object)\n            ├─ messages    last 16 turns kept verbatim\n            ├─ recall      everything older, embedded in Vectorize\n            ├─ facts       typed notes the assistant decided to save\n            └─ artifacts   Svelte 5 widgets compiled on the edge\n```\n\nEach turn runs through Workers AI. When the model calls the `panel` tool, the Worker compiles the generated Svelte 5 and mounts it next to the chat. When it calls `remember`, a typed fact is saved. As the conversation grows, older messages are embedded with bge-base-en and pushed into Cloudflare Vectorize; the model can recall them via `search_context`. Nothing is mocked.\n\n## Run\n\nRequires Bun, Node 22+, and a Cloudflare-authenticated `wrangler` with Workers AI access. Local development omits the optional Vectorize binding, so old messages are not searchable there; production creates and binds the index through Alchemy.\n\n```sh\nbun install\nbun run dev          # starts both the SvelteKit app and the Worker\n```\n\nOpen \u003chttp://127.0.0.1:5176\u003e. The live deployment lives at \u003chttps://loop.coey.dev\u003e.\n\nTry:\n\n\u003e Create a panel called build-status that lists three repos in cyan. Remember that cyan means a running experiment.\n\nYou will see, in this order:\n\n1. the message appear in **chat**;\n2. a `running…` placeholder while Workers AI works (you can send another message immediately);\n3. a compiled Svelte widget mounted in **artifacts**;\n4. a saved fact appear in **facts**;\n5. the exact generated `.svelte` under **source** with syntax highlighting.\n\nReload — everything survives.\n\n## Animation panels\n\nGenerated panels may import two animation libraries directly:\n\n```svelte\n\u003cscript\u003e\n  import * as THREE from \"three\";\n  // or: import { DotLottie } from \"@lottiefiles/dotlottie-web\";\n\u003c/script\u003e\n```\n\nThe iframe import map pins Three.js `0.179.1` and dotlottie-web `0.49.0` from\nesm.sh. The Worker enforces the import allowlist at compile time; arbitrary\npackage imports are rejected. Three.js panels are model-authored and must clean\nup render loops, observers, listeners, GPU resources, and renderers. Explicit\nLottie requests use a compact typed `lottie_panel` tool (`spinner`, `pulse`, or\n`signal`) so the model chooses intent and colors while Loop generates known-good\nLottie JSON and lifecycle cleanup; this avoids long, fragile source tool calls.\n\nAn empty loop offers two deterministic starter artifacts:\n\n- **Three.js orbital field** — a pointer-reactive, lit 3-D scene with particles.\n- **Lottie signal constellation** — declarative vector rings rendered from\n  embedded Lottie JSON.\n\nThey use the same compile, persistence, iframe, source viewer, and delete paths\nas model-authored artifacts; they are examples, not mocked previews. After ~16 turns, older messages start getting embedded into Vectorize; the model can search them on demand.\n\n## Verify\n\n```sh\nbun run check    # SvelteKit + Worker type-check\nbun run test     # unit tests\nbun run verify   # check + test + build (runs automatically on git push)\nbun run e2e      # real Workers AI: artifact, fact, durable reload\nbun run stress   # real inference + rolling window + Vectorize recall + export\n```\n\n`e2e` and `stress` call Workers AI and consume usage.\n\n## Ship\n\nCI is manual-only. `verify` runs locally on every `git push` via `.githooks/pre-push` (installed automatically by `bun install`). To deploy to \u003chttps://loop.coey.dev\u003e:\n\n```sh\nbun run ship    # verify + push + trigger deploy workflow + watch\n```\n\nSkip the local gate with `git push --no-verify` or `LOOP_SKIP_VERIFY=1`. Trigger workflows by hand any time with `gh workflow run {deploy,verify,inference} --repo acoyfellow/loop`.\n\n## Layout\n\n```\nsrc/routes/+page.svelte     UI: chat, artifacts, source, inspector\nsrc/routes/+page.server.ts  load chat snapshot\nsrc/routes/data.remote.ts   getThread, sendMessage, resetThread\nsrc/lib/highlight.ts        Shiki (vitesse-dark, lang=svelte) lazy loaded\nworker/index.ts             HTTP boundary + owner routing\nworker/LoopDO.ts            Loop extends Think — messages, tools, facts, artifacts, recall\nworker/recall.ts            Vectorize-backed long-term memory (bge-base-en, top-k)\nworker/panels.ts            Svelte 5 compile\nworker/types.ts             vocabulary\nwrangler.local.jsonc        local DO + remote Workers AI (optional MEMORY binding omitted)\nalchemy.run.ts              Cloudflare deployment graph\ntests/                      unit + Playwright + API stress\n```\n\nThat is the whole core.\n\n## How memory works\n\nThere is exactly **one chat session per account**. No conversation list, no folders, no compaction, no auto-summarization.\n\n- The most recent **16 messages** stay verbatim in the prompt every turn.\n- When the count exceeds 16, the oldest pair is embedded (Workers AI `@cf/baai/bge-base-en-v1.5`, 768-dim) and upserted into a Cloudflare Vectorize index, namespaced by owner.\n- The model gets a `search_context` tool. When the user asks about something out-of-window, it queries Vectorize, top-k 5, and pulls the matches back into the prompt.\n- The **facts** table is the model's deliberate memory: typed entries (`preference`, `decision`, `fact`, `failure`, `open_loop`) created when the user explicitly says \"remember…\". These never get rolled out.\n- **`reset`** wipes everything — messages, artifacts, facts, and Vectorize entries — and starts the same single session over.\n\n## Contract\n\n| Surface      | Behavior                                                                                       |\n| ------------ | ---------------------------------------------------------------------------------------------- |\n| Chat         | One SQLite-backed Durable Object per authenticated owner                                       |\n| Inference    | Workers AI binding (default `@cf/moonshotai/kimi-k2.6`)                                        |\n| Window       | Last 16 messages kept verbatim; older ones evicted to Vectorize each turn                      |\n| Recall       | Workers AI embeddings (`@cf/baai/bge-base-en-v1.5`) into a Vectorize index, scoped by owner    |\n| Facts        | Typed records (`preference`, `decision`, `fact`, `failure`, `open_loop`); `wrong` / `forgotten` are signals, not deletions |\n| Artifacts    | Model emits complete Svelte 5 source; Worker compiles it; iframe mounts the result             |\n| Animation imports | Allowlisted `three` and `@lottiefiles/dotlottie-web`, pinned through the iframe import map |\n| Idempotency  | `requestId` on `/api/messages` prevents duplicate turns                                        |\n| Export       | `GET /api/export` returns the full chat history and every artifact revision                    |\n\n## Boundaries\n\n- Generated Svelte runs in a sandboxed iframe with no owner credentials or Worker bindings.\n- Backend mutations are fixed typed actions, not generated code.\n- Auth: Better Auth + D1. Local development uses a fixed owner so login is not required.\n- Production sign-up is gated by an invite password (`LOOP_INVITE_PASSWORD`). Sign-in for existing accounts is unaffected. When the env var is unset, sign-up is open — only use that locally.\n\n## Provenance\n\n`loop` originally prepared repositories for repeated agent runs. This is the same idea at app scale: the vessel is now one durable owner session the model can read, write, and rebuild artifacts inside.\n\nPatterns reused:\n\n- [`remote`](https://github.com/acoyfellow/remote) — authenticated SvelteKit + Durable Objects shell.\n- [`svelte-edge`](https://github.com/acoyfellow/svelte-edge) — Svelte 5 source compiled at the edge.\n- [`deja`](https://github.com/acoyfellow/deja) — durable selected memory discipline.\n\nMIT.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Facoyfellow%2Floop","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Facoyfellow%2Floop","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Facoyfellow%2Floop/lists"}