ClipLoop is building a simpler way for brands, businesses, and creators to create short form promo content faster.
- Premium studio dashboard at
/appwith:- dark sidebar + mobile drawer
- clean command/search style top bar
- quick action cards for create/chat/project/import paths
- projects, credits, recent outputs, recent activity, and usage overview sections
- Guided create flow at
/app/create:- rough prompt input
- prompt-to-brief upgrade
- editable brief fields (channel, tone, duration, style, CTA, caption hint)
- pre-generation credit cost visibility
- final billable generation + render with result preview/download
- Chat workspace at
/app/chatswith:- conversation list
- free chat mode + paid generation modes
- in-thread result cards with previews and receipts
- Projects hub at
/app/projectsfor quick workspace access - Guided onboarding that captures business profile + preferred channels
- Website ingestion pipeline (code-first crawl + text extraction, no scraping SaaS)
- Business context storage:
- structured profile fields on projects
- persisted website context documents
- Conversation/message/chat-job persistence
- Server-side chat orchestration:
- loads business context
- interprets channel intent
- generates promo draft
- triggers existing render infrastructure
- returns results in-thread with preview + download link
- Provider-agnostic LLM layer with Mistral support and mock fallback
- Existing generation/render/schedule/publish/tracking/iteration systems kept behind the scenes
- Next.js App Router + TypeScript
- Tailwind CSS
- Postgres
- Drizzle ORM
- Zod validation
- FFmpeg (system dependency for rendering)
- Optional Mistral chat provider via REST API
Primary authenticated experience:
/app: studio dashboard (operational home)/app/create: guided prompt-to-video path/app/chats: chat strategy and generation workspace/app/projects: project list and entry point into project detail pages/dashboard/manual-queueand/dashboard/settings: operational surfaces retained- onboarding-first behavior still applies for users without project context
Secondary surfaces still available:
- settings, manual queue, legacy workflow pages
- existing backend loops remain operational and reusable by chat orchestration
- Real data-backed:
- credits balance + plan status (
credit_accounts, plan state) - usage overview (
usage_counters+ plan limits) - projects list (
projects) - recent outputs (
content_items+content_assetsthumbnails where available) - recent activity (
credit_ledger_entries)
- credits balance + plan status (
- Graceful fallback states:
- outputs without thumbnails show a clean "No preview" tile
- empty projects/activity/outputs sections show actionable CTAs, not fake metrics
The authenticated product shell now follows a restrained, premium visual language inspired by Mistral admin:
- white/off-white surfaces
- dark text and dark primary actions
- soft borders and generous spacing
- minimal decoration and calmer hierarchy
- mobile-first chat layout with fixed composer and clean drawer navigation
- shared primitives for cards/inputs/badges/nav states to keep every page visually consistent
- quiet status/error/success blocks with readable contrast and no loud visual noise
ClipLoop monetization now follows:
- Chat is free (normal conversation does not consume credits)
- Paid value actions consume credits:
- promo copy generation consumes generation credits
- generate-video consumes generation + render credits
Credit accounting is now ledger-backed:
credit_accountsstores current generation/render balances (source of truth)credit_ledger_entriesstores immutable debits/credits with reason, amount, timestamp, and balance snapshot- monthly plan grants are applied as ledger credits per month window
- chat result cards include receipt metadata for paid actions
- settings now includes recent transaction history
- paid action charging is idempotent by
chat_jobreference keys to avoid duplicate debits on retries - chat paid actions (
generate_copy,generate_video) use ledger affordability as the charging gate - non-chat paid actions also use ledger affordability/charging gates:
generate-posts(strategy cycle pack)regenerate(single post)render(single and cycle render paths)generate-nextiteration pack generation
- billing policy is centralized in
src/domains/credits/policy.tsto avoid cost/rule drift
User-facing plan names:
Free: chat access + capped monthly creditsPro: higher generation/render credit limits and multi-project usage
Compatibility note:
- Some internal billing/domain identifiers still use
starterfor Lemon Squeezy/webhook compatibility. - UI copy and product messaging use Pro.
- Existing
usage_countersare still updated for compatibility/reporting during transition. - Charging decisions and displayed balances are ledger-driven (
credit_accounts+credit_ledger_entries), not counter-driven. - Non-billable operational workflows may still use existing usage counters during transition.
usage_countersno longer block billable generation/render decisions.- Scheduling/publishing limits remain non-billing operational limits in this pass.
Active policy coverage:
- Billable:
- chat
generate_copy(generation 1) - chat
generate_videogeneration step (generation 1) - chat
generate_videorender step (render 1) - strategy cycle post generation (generation 5)
- content item regenerate (generation 1)
- iteration next-pack generation (generation 5)
- content item render (render 1)
- chat
- Non-billable:
- plain chat
- export bundle
- direct Instagram publish
- manual mark-posted / queue operations
Billing hardening tests:
npm run test:billing- The suite runs DB-backed integration tests for idempotent charging across generate-posts, regenerate, render, and generate-next.
- If Postgres or required migrated tables are unavailable, tests are reported as skipped.
The authenticated UX is now focused on a cleaner mobile-first app shell:
- primary workspace at
/app - sidebar/drawer navigation for secondary surfaces
- integrated ClipLoop branding
- clearer in-chat action modes and limit messaging
- calmer top navigation, tighter spacing rhythm, and cleaner message/composer hierarchy
- same black/white enterprise-style surface language across pricing, settings, manual queue, and billing outcome views
For a request like:
- "Generate a WhatsApp promo video for our weekend sale"
ClipLoop now:
- Loads the user’s primary business context (structured + ingested website text)
- Infers target channel intent
- Generates promo script/caption/CTA
- Creates a backend content item and triggers render (legacy/HyperFrames adapter)
- Persists chat job + messages
- Returns result card in-thread with video preview, caption, CTA, channel, download link
- Install dependencies
npm install- Configure env
cp .env.example .env-
Ensure Postgres is running and
DATABASE_URLis valid. -
Run migrations
npm run db:migrate- Optional seed
npm run db:seed- Start app
npm run devOpen http://localhost:3000.
- macOS (Homebrew):
brew install ffmpeg - Ubuntu/Debian:
sudo apt update && sudo apt install -y ffmpeg - Windows (winget):
winget install Gyan.FFmpeg
If FFmpeg is missing, render APIs return a clear error.
ClipLoop remains the workflow/product layer. HyperFrames is integrated as an optional composition/render engine behind the existing render flow.
What this path does:
- adds renderer adapter routing:
legacyorhyperframes - builds a server-side composition package from content item data
- uses one initial HyperFrames template (
hf_promo_v1) for short promo clips - uses channel-aware caption/CTA variants and target-channel context
- writes output video + thumbnail back into existing
content_assetsflow
Current HyperFrames use case:
- short promo clip from:
- hook
- channel caption
- channel CTA
- business name
- optional
logo_urlandbackground_asset_urlfromvoice_prefs_json - target channel (
instagram/tiktok/whatsapp)
Environment setup:
HYPERFRAMES_ENABLED=trueto allow HyperFrames backendHYPERFRAMES_BIN=hyperframes(or custom CLI path)
Failure behavior:
- if HyperFrames is disabled or CLI is missing, render fails with explicit error codes
- no fake success path is used
ClipLoop now routes model calls through an internal provider interface:
mistralprovider for production chat generation (default)mockprovider for deterministic local/dev behavior when explicitly enabled
Environment:
LLM_PROVIDER=mistral|mock(default:mistral)MISTRAL_API_KEY=...(required whenLLM_PROVIDER=mistral)MISTRAL_MODEL=mistral-small-latest(override as needed)MOCK_LLM=falseby default; mock behavior is only used whenLLM_PROVIDER=mockor explicitly forced in non-mistral mode
Business logic stays provider-agnostic so future self-hosted/open-weight backends can be swapped in without rewriting orchestration logic.
- Generate posts for a weekly cycle.
- Render each post (or render all).
- Approve one post (or approve all).
- Schedule publish times (single or bulk).
- Run due jobs manually from the weekly page (
Run due jobs now). - Items move through publish states and end at
published.
Publishing mode selection:
- If a project has an active, valid Instagram channel, jobs use the real Instagram publisher.
- If no valid channel exists and
MOCK_MODE=true, jobs fall back to mock publishing. - If no valid channel exists and
MOCK_MODE=false, jobs fail clearly with channel errors.
ClipLoop supports one real publishing channel per project in MVP: Instagram.
Minimum setup:
- Set
INSTAGRAM_CLIENT_ID,INSTAGRAM_CLIENT_SECRET,INSTAGRAM_REDIRECT_URI, andENCRYPTION_SECRET. - In your Meta app config, add the callback URL:
http://localhost:3000/api/integrations/instagram/callback(local)
- From the project page, click Connect Instagram.
- After callback, the project page shows channel status (active/expired/invalid/disconnected).
Token safety:
- Access tokens are encrypted at rest using
ENCRYPTION_SECRET. - Tokens are decrypted only during publish/connect operations.
Local/dev testing:
- With no Instagram credentials and
MOCK_MODE=true, the weekly loop still runs via mock publisher. - To test real publish, connect a real Instagram channel and run due jobs from the weekly page.
Each content item has a tracking slug and redirect link:
/r/<trackingSlug>
Redirect behavior:
- logs click event with
click_id - redirects to destination URL
- appends query params:
utm_source=cliplooputm_medium=short_formutm_campaign=<tracking_slug>clp_post=<content_item_id>clp_click=<click_id>
Attribution priority:
clickIdcontentItemIdprojectId
Use the helper script on your site:
<script src="https://YOUR_CLIPLOOP_DOMAIN/api/tracking/script.js" defer></script>It stores clp_click to localStorage/cookie and exposes:
window.ClipLoopTracking.getClickId()
POST /api/track/conversion
{
"clickId": "<from clp_click>",
"eventType": "signup",
"externalUserId": "user_123"
}POST /api/track/revenue
{
"clickId": "<from clp_click>",
"source": "manual",
"amount": 4900,
"currency": "USD",
"eventName": "purchase"
}POST /api/strategy-cycles/[strategyCycleId]/rollupGET /api/strategy-cycles/[strategyCycleId]/performance
Score formula:
(revenue * 100) + (signups * 20) + (clicks * 2) + (ctr * 5)
Classification:
- winner / neutral / loser by relative weekly ranking.
- Publish mock content.
- Generate clicks/conversions/revenue.
- Run weekly rollup.
- Click Analyze this week.
- Inspect winners/losers, improved hooks, and angle mutations.
- Click Generate next week.
- Review the next cycle and derived posts.
Notes:
- Next cycle source is
iteration. - Next cycle week starts at current week + 7 days.
parent_content_item_idtracks lineage from winner posts to derived next-week posts.- Iteration is manual in MVP (no autonomous job runner).
- Publish mock content item in dashboard.
- Click its tracking link (
/r/<slug>). - Send conversion with returned
clp_click. - Send revenue event.
- Run rollup for the week.
- Run analysis + generate next cycle.
- Verify metrics/analysis on week/project pages.
Publish statuses:
draft,approved,scheduled,publishing,published,failed,skipped
Queue statuses:
pending,running,completed,failed,dead
Rendered outputs are stored locally under:
public/generated/content-items/<contentItemId>/<timestamp>/rendered.mp4public/generated/content-items/<contentItemId>/<timestamp>/thumbnail.jpg
- Generation: projects/strategy/posts/regenerate
- Rendering: render one/all + assets
- Publishing workflow: approve/schedule/run jobs
- Tracking: redirect + script + conversion/revenue ingest
- Metrics: rollup + cycle/project performance
- Iteration: analyze + generate-next + analysis + project next-cycle
- Only Instagram real publishing is supported today.
- TikTok publishing is not implemented yet.
- TikTok and WhatsApp remain manual render/export-first for posting.
- HyperFrames integration is server-side template composition only; no in-app visual editor yet.
- HyperFrames preview UI is not exposed yet (adapter is structured to support it later).
- No cron or distributed workers yet.
- Attribution is intentionally simple.
- No advanced analytics dashboards/charts.
- Iteration is deterministic/mock-driven and manually triggered.
ClipLoop now has a public-facing launch surface intended to collect serious beta users and paid interest without overselling missing features.
Public routes:
/landing page/pricing/request-access
Public positioning:
- Short form promo content for brands, businesses, and creators.
- one weekly generated promo pack
- render, approve, schedule, publish, track, learn, repeat
- invite-only beta
- cheap, opinionated, intentionally narrow
Good fit:
- Brands and small businesses
- Creators and solo builders
- App teams with distribution goals
- operators who want one weekly loop instead of a broad social suite
Not a fit:
- agencies managing many brands at full enterprise scale
- large social teams
- users expecting unlimited generation or fully polished multi-channel automation today
Projects now include a business profile that feeds strategy and post generation:
- project type (
business,creator,app) - business identity and category
- city/state and target audience
- primary offer, price range, tone, and CTA
- Instagram/WhatsApp/web context
- normalized preferred channels (
instagram,tiktok,whatsapp) and language style (english,pidgin,mixed)
Generation behavior is now biased toward:
- short promo content
- offer-led hooks
- urgency/scarcity framing when appropriate
- social-proof style angles
- practical business friendliness
- English/Pidgin output based on project language style
ClipLoop now stores preferred channels as structured data and uses them directly in generation.
Channel behavior in this pass:
- Instagram: cleaner promo captions, polished CTAs, stronger visual promo framing.
- TikTok: sharper opening hooks, faster short-form pacing, creator-native phrasing.
- WhatsApp: shorter status-friendly copy, direct sales tone, less generic marketing language.
Generated posts now support lightweight per-channel output fields:
channel_captionsvariantschannel_cta_textvariants
Each content item now persists targetChannel (instagram, tiktok, whatsapp) as explicit workflow state.
targetChannel effects:
- generation assigns deterministic defaults from project preferred channels
- iteration preserves or sensibly assigns channel intent on next-cycle posts
- dashboard exposes and allows per-item channel switching
- preview caption/CTA and render defaults follow persisted channel
- each item also persists
publishStrategy(direct_instagramormanual_export) - direct scheduling/publishing remains Instagram-only; TikTok/WhatsApp are manual/export-first
Manual-export items now support first-class downloadable packaging.
Bundle contents:
- rendered video (
assets/video.mp4) when available - thumbnail (
assets/thumbnail.jpg) when available caption.txt(channel-aware caption)cta.txt(channel-aware CTA)manifest.json(item/project/channel/asset metadata)README.txt(human-readable publishing notes)
This workflow is intentionally local/open-source-first:
- ZIP packaging is server-side using open-source Node tooling (
archiver) - no paid export SaaS
- no API-key-based packaging dependency
Core workflows are unchanged:
- render, approval, scheduling, publish, tracking, and iteration continue to run on the same pipeline.
ClipLoop now includes a dedicated dashboard queue for manual posting operations:
/dashboard/manual-queue
Queue scope:
- only items with
publishStrategy=manual_export - direct Instagram items stay in the existing direct publish path
Manual statuses:
ready_for_export: item is in manual flow and awaiting bundle export/postingexported: operator exported the ZIP bundleposted: operator confirmed platform posting manually
Queue actions:
- filter by target channel (
instagram,tiktok,whatsapp) - filter by manual status
- sort newest/oldest
- render-for-export when render is still pending
- export bundle using existing ZIP packaging flow
- mark item as posted (operator-confirmed, not API-verified)
Publish guardrails:
- direct scheduling/publishing remains Instagram-only for
direct_instagramitems - TikTok and WhatsApp remain manual/export-first in this pass
ClipLoop is designed as a paid product using open-source/self-hostable building blocks wherever practical.
ClipLoop now has explicit internal layer boundaries to support long-term platformization without breaking the current app:
src/app+src/components: first-party product UX and route orchestrationsrc/core: reusable open-core engine contracts/primitives (LLM, render, billing policy, context ingestion contracts)src/gateway: hosted-gateway boundaries (API-key auth, orchestration, provider access, render execution, credit guard) with local adapters for now
In this pass, compatibility wrappers keep existing imports and behavior stable while moving reusable seams into src/core and hosted seams into src/gateway.
Current local/open-source-first subsystems:
- FFmpeg legacy renderer
- HyperFrames renderer adapter (local CLI path)
- HTML template-based composition
- server-side composition generation
- server-side manual export ZIP packaging
- Next.js + Postgres + Drizzle stack
ClipLoop now supports invite-only product access plus hard usage enforcement for sellable MVP packaging.
- Controlled by
INVITE_ONLY_MODE(defaulttrue). - When enabled, only users who are beta-approved (or paid starter) can use product workflows.
- Non-approved users see a waitlist/request-access screen in dashboard.
- In
MOCK_MODE, the demo user is auto-approved to keep local dev frictionless.
free: account exists but product access can be gated.beta: approved invite-only testers with production-like limits.starter: paid $5/month Starter plan with the same hard limits in this slice.
- 1 active project
- 5 posts generated per week
- 20 posts generated per month
- 3 manual regenerations per week
- 20 renders per month
- 20 publishes per month
- 1 connected channel (future-compatible limit placeholder)
Usage counters are updated by generation/regeneration/render/publish flows and enforced in API-triggered workflows. Weekly and monthly usage are stored separately, so the current window summaries do not double count cross-period actions.
POST /api/billing/checkoutcreates a real hosted Lemon Squeezy checkout for the Starter variant./pricingnow exposes a live Starter CTA./billing/successand/billing/cancelprovide post-checkout return states.POST /api/webhooks/lemonsqueezyverifies theX-Signatureheader and syncs subscription lifecycle changes into the existing account model.POST /api/billing/portalrefreshes a Lemon Squeezy customer-portal URL from the current subscription and redirects the user into self-serve billing management.
subscriptionsnow stores Lemon Squeezy IDs, provider status, management URLs, and current period dates alongside the earlier placeholder billing fields.- Webhooks are the source of truth for Starter activation and downgrade decisions.
- Effective plan is derived from user beta approval plus the synced subscription status.
GET /api/me/planandGET /api/me/usageexpose plan/usage for UI surfaces.
- Active paid Starter access grants product access even when invite-only mode is enabled.
- Beta-approved users keep beta access unless a paid Starter subscription temporarily supersedes it.
- If a Starter subscription fully expires, access falls back to
betawhen the user is beta-approved, otherwise to gatedfree. - Cancel-at-period-end subscriptions keep Starter access until the synced current period end.
POST /api/access/requeststores waitlist/access requests.- Repeat requests for the same email while still pending are deduped instead of creating noisy duplicates.
- In mock mode only:
POST /api/dev/approve-userwith:
{
"email": "user@example.com",
"plan": "beta"
}This sets beta approval and plan state without building a full admin panel.
/dashboard/projects/newnow guides users through the workflow more clearly before their first strategy cycle./dashboard,/dashboard/projects/[projectId], and/dashboard/settingsshow plan state, usage remaining, and product-readiness status so the MVP feels operational.
Add these to .env:
NEXT_PUBLIC_APP_URL=http://localhost:3000
LEMON_SQUEEZY_API_KEY=
LEMON_SQUEEZY_STORE_ID=
LEMON_SQUEEZY_STARTER_VARIANT_ID=
LEMON_SQUEEZY_WEBHOOK_SECRET=- Run the app locally.
- Expose your local app publicly with a tunnel such as ngrok or Cloudflare Tunnel.
- Create a Lemon Squeezy webhook pointing to:
https://YOUR_PUBLIC_URL/api/webhooks/lemonsqueezy
- Subscribe at minimum to:
subscription_createdsubscription_updatedsubscription_cancelledsubscription_resumedsubscription_expiredsubscription_pausedsubscription_unpaused
- Use a test-mode Starter variant in Lemon Squeezy if you want to exercise the flow without charging real cards.
- ClipLoop currently supports one paid plan only: Starter monthly.
- The app uses Lemon Squeezy hosted checkout and customer-portal links rather than a custom in-app billing portal.
- Real auth is still minimal, so in non-mock environments the checkout launcher relies on the email entered at checkout start to create or match the account record.