An operator desk for self-updating agent skills, built with Next.js.
Product model · Architecture · Local dev · Deploy
The name "Loop" was inspired by Aryan Mahajan — thanks for the spark.
It does four jobs:
- shows a catalog of skills you can browse, track, import, or write
- refreshes tracked skills from external sources and saves each refresh as a new version
- exposes the update run itself with logs, source scans, summaries, and diffs
- lets you run agents against those skills, attached prompts, and imported MCP servers
- skill — the main knowledge object. Has a body, description, tags, category, sources, automation settings, updates, and versions. All skills live in Supabase.
- source — a URL the refresh pipeline scans. Can be
rss,atom,docs,blog,github, orwatchlist. - update — one refresh pass over a tracked skill. Stores summary, what changed, experiments, source items, changed sections, editor model, and whether the body changed.
- version — every saved skill revision gets a stable URL like
/skills/frontend-frontier/v4. - automation — a schedule that refreshes a skill on a cadence. Stored as a JSONB column on the skill in Supabase (
skills.automation). - MCP — an imported server definition that can be attached to agents.
httpandstdioMCPs can execute; other transports are treated as metadata. - usage event — a persisted observability record for page views, copies, searches, skill actions, agent runs, and API calls.
- repo — a
SKILL.mdfound inside this project (dev only, synced to DB on refresh). - codex — a
SKILL.mdfound in~/.codex/skills(dev only, synced to DB on refresh). - user — a skill created or tracked inside Loop. This is the primary production origin.
- remote — a skill imported from a URL and normalized into Loop's versioned format.
User and remote skills win over repo and Codex skills when slugs overlap. The tracked version should be the one you actually operate.
Loop uses Supabase (Postgres) as the single source of truth. There are no local filesystem stores in production.
| Table | What it holds |
|---|---|
skills |
All skill data: body, metadata, sources JSONB, automation JSONB, updates JSONB |
skill_versions |
Immutable version snapshots |
categories |
Category definitions and source configs |
mcps |
MCP server definitions |
briefs |
Daily category signal briefs |
loop_runs |
Refresh run logs and outcomes |
usage_events |
Observability telemetry |
Row-level security (RLS) is enabled on all tables. Anonymous access is blocked by default.
Loop uses Clerk for user authentication. Sign-in/sign-up are managed flows. Billing metadata (Stripe customer ID, Connect account ID) is stored on the Clerk user profile.
Stripe handles subscription checkout, portal sessions, webhook ingestion, and Connect payouts for skill sellers.
Automations are stored as part of each skill's automation JSONB column in Supabase:
type SkillAutomationState = {
enabled: boolean;
cadence: "daily" | "weekly" | "manual";
status: "active" | "paused";
prompt: string;
lastRunAt?: string;
};The daily cron (GET /api/refresh) checks which skills have active automations that are due, fetches signals from their sources, runs an agent to draft a revision, and saves the result as a new version — all against Supabase.
There are no TOML files, no local filesystem paths, and no hardcoded directories in the automation system.
Route: /
The home desk is the shortest path: browse the catalog, filter by category, search by name/tag/category, open a skill, or track it into your editable set.
Route: /skills/new
You can import a remote skill from a URL or create a new user skill from scratch. Both normalize into the same tracked, versioned data model.
Routes: /skills/[slug], /skills/[slug]/[version], /settings
Tracked skills expose:
- the prompt and how to use the skill
- tracked sources
- automation settings (editable from calendar, sidebar, and dashboard)
- latest update summary with before/after diff
- version history
- usage and recent calls
Settings pages provide:
/settings/automations— create, edit, pause, and schedule automations with a monthly calendar view/settings/refresh— trigger manual full refreshes/settings/health— system-wide usage, API traffic, and route breakdowns/settings/subscription— manage your Operator plan/settings/connect— Stripe Connect onboarding for payouts
Routes: /sandbox, /agents
The Sandbox provisions a secure Vercel Sandbox session. The Agent Studio lets you choose a provider and model (Vercel AI Gateway, OpenAI, OpenRouter, Groq, Together AI, or Ollama), attach skills and MCP servers, review assembled context including daily briefs, and chat with the agent. Supports code execution in Node.js and Python runtimes.
The refresh pipeline is the center of the product.
- Load tracked skill documents from Supabase
- Decide which skills are due for refresh (check
automation.enabled,cadence,lastRunAt) - Fetch signals from each skill's source watchlist
- Run a research-first agent that analyzes signals, then searches the web via Firecrawl (up to 4 searches per run) and fetches full page content as clean markdown
- The agent revises the skill body based on evidence from both tracked sources and live web research
- Save a new version (immutable — never mutates the old one)
- Persist run logs, summaries, diffs, and source results
- Record the run outcome
The agent has a dynamic step budget computed from the number of sources and search budget, with 5 steps reserved for the revision phase so research never crowds out the actual skill update.
Relevant files:
lib/refresh.ts— the main refresh pipelinelib/skill-editor-agent.ts— the research-first agent (step budget, tool wiring, system prompt)lib/agent-tools/— agent tools:web-search.ts,fetch-page.ts,firecrawl.ts,add-source.tslib/source-signals.ts— signal fetching from sourceslib/loop-updates.ts— update normalizationlib/text-diff.ts— before/after diffingapp/api/refresh/route.ts— cron endpoint
| Flow | Endpoint | What happens |
|---|---|---|
| User creates from scratch | POST /api/skills |
Validates input, inserts into Supabase with origin: "user" |
| User tracks a catalog skill | POST /api/skills/track |
Merges skill + category sources, writes to Supabase |
| Import a remote skill | POST /api/imports |
Fetches, normalizes, inserts into Supabase |
| Filesystem sync (dev only) | refreshLoopSnapshot() |
Reads SKILL.md files, upserts into Supabase |
| Flow | Trigger | What happens |
|---|---|---|
| Daily cron | GET /api/refresh (Vercel cron) |
Checks due automations, fetches signals, agent rewrites, saves to Supabase |
| Manual refresh | POST /api/admin/loops/update |
Same pipeline, triggered on demand |
| Edit automation | PATCH /api/automations/[slug] |
Updates skills.automation JSONB in Supabase |
| Disable automation | DELETE /api/automations/[slug] |
Sets automation.enabled = false in Supabase |
| Create automation | POST /api/automations |
Sets skills.automation JSONB in Supabase |
The lib/db/seed-data/ directory contains bootstrap data for development: skill source configs, MCP definitions, and skill definitions. These are applied via CLI scripts (npx tsx lib/db/seed-automations.ts) and are never imported by any production code path. In production, all data flows through the API → Supabase.
Loop stores usage and operational telemetry in Supabase.
What gets recorded: page views, interactions, prompt/URL copies, searches, skill CRUD, automation runs, agent runs, API calls with route/method/status/duration.
Where it shows up:
/settings/health— system-wide usage, route activity, 24h rolling charts- each skill detail page — per-skill usage
- refresh dashboards — loop run logs, source scans, and diffs
NEXT_PUBLIC_SITE_URL=http://localhost:3000
CRON_SECRET=replace-meNEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=
CLERK_SECRET_KEY=
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-upNEXT_PUBLIC_SUPABASE_URL=
NEXT_PUBLIC_SUPABASE_ANON_KEY=
SUPABASE_SERVICE_ROLE_KEY=OPENAI_API_KEY=
LOOP_MODEL=gpt-5-mini
AI_GATEWAY_API_KEY=
FIRECRAWL_API_KEY=
OPENROUTER_API_KEY=
GROQ_API_KEY=
TOGETHER_API_KEY=AI_GATEWAY_API_KEY is required for automations (routes through Vercel AI Gateway). FIRECRAWL_API_KEY powers web search and page scraping during agent runs. Without it, fetch_page falls back to plain HTTP.
STRIPE_SECRET_KEY=
STRIPE_WEBHOOK_SECRET=
STRIPE_PRICE_OPERATOR=pnpm install
pnpm devUseful commands:
pnpm test # run tests
pnpm typecheck # TypeScript check
pnpm build # production buildnpx tsx lib/db/seed-automations.ts # apply sources + automation config to skills
npx tsx lib/db/seed-skills.ts # seed skill definitions
npx tsx lib/db/seed-mcps.ts # seed MCP server definitionsThese scripts are idempotent and safe to re-run.
/— catalog desk/skills/new— import or create/skills/[slug]— redirect to latest version/skills/[slug]/[version]— versioned skill detail/sandbox— agent sandbox/settings— automations, refresh, health, subscription, connect
GET /api/search— catalog searchPOST /api/skills— create a user skillPOST /api/skills/track— track a catalog skillPOST /api/imports— import a remote skill or MCPGET /api/refresh— cron-triggered refreshPOST /api/admin/loops/update— manual skill refreshGET /api/automations— list automations (derived from skills)POST /api/automations— create an automation on a skillPATCH /api/automations/[slug]— update automation configDELETE /api/automations/[slug]— disable an automationPOST /api/agents/run— run an agent with attached skillsPOST /api/chat— sandbox chatPOST /api/usage— record usage eventsGET /api/models— list available AI modelsGET /api/billing/checkout— Stripe checkout sessionGET /api/billing/portal— Stripe customer portalPOST /api/stripe/webhook— Stripe webhook handler
This app is designed for Vercel but runs locally without Vercel services.
For a production deploy:
- Set
NEXT_PUBLIC_SITE_URLto your production domain - Set
CRON_SECRETfor the daily refresh cron - Configure Supabase env vars (URL, anon key, service role key)
- Configure Clerk env vars (publishable key, secret key)
- Configure
AI_GATEWAY_API_KEYfor automations andFIRECRAWL_API_KEYfor web research - Configure Stripe keys if billing is enabled
- The cron schedule is in
vercel.json
Tests cover:
- automation cadence mappings, schedule formatting, and calendar scheduling
- seed data validation (minimum 4 sources per skill, actionable prompts)
- admin session helpers
- remote import parsing
- loop update normalization
- user skill versioning and updates
- settings navigation
- usage overview computations
Run all tests:
pnpm test| File | Variant |
|---|---|
public/brand/loop-mark.svg |
Gear mark — dark chip (for light backgrounds) |
public/brand/loop-mark-light.svg |
Gear mark — light chip (for dark backgrounds) |
public/brand/loop-icon-accent.svg |
App icon — accent orange background with white gear |
app/icon.svg |
Favicon — dark background with white gear |
The mark is a golden-ratio gear with a detachable chip. The animated React version lives in components/loop-logo.tsx (spinning gear + floating chip on hover), with path data in lib/loop-logo-paths.ts.
OG images are generated dynamically at /og via next/og (app/og/route.tsx). The route accepts optional title, description, and category query params. When none are provided it renders the default card.
The card uses:
- warm dark gradient background with radial orange glow
- the gear icon as a header lockup
Neue Montreal(Book + Bold) loaded from local TTF files inapp/og/- a product screenshot from
/images/og.pngbleeding off the right edge
SEO metadata helpers (titles, descriptions, OG images, JSON-LD) are centralized in lib/seo.ts.
Loop scans skills, lets you track or import them, refreshes them from watched sources and live web research via Firecrawl, saves every refresh as a versioned revision, records the run, and exposes the whole thing in one operational UI — backed entirely by Supabase.