Skip to content
Skillv1.0.0

openstory

Work with OpenStory (github.com/openstory-so/openstory), the open-source AI script-to-video sequence platform built on Bun + TanStack Start + Cloudflare Workers (D1, R2, Workflows, Durable Objects) wi

by akillness(0) 0 installs
Free
Sign in to install

Free account. Installing gives you the manifest plus copy-paste snippets.

See reviews

About

Imported from akillness/jeo-skills (.agent-skills/openstory/SKILL.md). Install upstream with npx skills add akillness/jeo-skills --skill openstory. Copyright stays with the author.

OpenStory — AI script-to-video sequence platform

OpenStory turns a written script into a styled video sequence: it splits the script into scenes, casts characters and locations from reusable team libraries, builds visual/motion/music prompts, renders frames through Fal.ai, animates them into motion clips, scores them, and merges the result. The whole app is a single Cloudflare Worker (src/server.ts) — D1 for data, R2 for media, 33 named Cloudflare Workflows for durable generation, and a Durable Object for SSE progress. Local dev runs that same Workerd runtime through Miniflare, so there is no "works locally, breaks in prod" gap.

When to use this skill

  • Cloning, bootstrapping, or running OpenStory locally (bun dev), or wiring the FAL_KEY / OPENROUTER_KEY needed for generation
  • Tracing or debugging the storyboard pipeline: why a sequence is stuck, which phase failed, what a workflow step actually produced
  • Adding or changing a Cloudflare Workflow, or hitting the WorkflowScopedDb / mid-run-read / replay-idempotency rules
  • Adding, hiding, or repricing an image / image-to-video / audio / LLM model
  • Changing the Drizzle schema or shipping a D1 migration safely
  • Deploying: deploy button, Workers Builds, PR previews, manual prod deploy
  • Contributing a PR (branch naming, Lefthook gates, pre-push checks)
  • Diagnosing one of the documented traps (bun test vs bun run test, remote D1 binding leak, nested migration files, silent cron drift, empty pricing)

When not to use this skill

  • Generic "make me an AI video" requests with no OpenStory repo involved → use video-production, vox-director, or video-shotcraft
  • Local desktop/timeline video editing → opencut, palmier-pro
  • Generic Cloudflare Workers/D1/Wrangler questions unrelated to this codebase → use the Cloudflare docs directly; this skill only encodes OpenStory's own contracts
  • Generic TanStack Start / Drizzle / Better Auth tutorials → those belong to their own docs; here they only appear as OpenStory conventions

Instructions

Step 1: Pick exactly one mode before touching anything

Mode Use when Go to
run-local first run, env keys, "nothing generates" Step 2
pipeline-trace a sequence is stuck/wrong, you need phase-level truth Step 3
workflow-authoring adding or editing src/lib/workflows/*-workflow.ts Step 4
model-catalog add/hide/reprice an image, video, audio, or LLM model Step 5
schema-migration Drizzle schema change or a D1 migration Step 6
deploy deploy button, Workers Builds, PR preview, manual prod Step 7
contribute opening a PR against upstream Step 8

Do not blend modes. If two apply, do the read-only one first.

Step 2: run-local — get a working local stack

git clone https://github.com/openstory-so/openstory.git
cd openstory && bun install && bun dev     # http://localhost:3000

bun dev is self-bootstrapping: scripts/ensure-env.ts writes .env.local with generated BETTER_AUTH_SECRET / API_KEY_ENCRYPTION_KEY, then db:migrate:localdb:seed:localvite dev. No Docker, no external DB, no Cloudflare account.

Generation stays dark until you add keys — bun setup (interactive) or paste into .env.local:

  • FAL_KEY — image, video, audio (and LLM via fal's OpenRouter endpoint)
  • OPENROUTER_KEY — LLM script analysis

Read the startup banner. bun dev prints its wrangler bindings. If DB shows REMOTE, kill the server immediately — that is the prod-D1 leak described in references/troubleshooting.md.

Full script/env tables: references/commands.md. Read-only host check: bash .agent-skills/openstory/scripts/openstory.sh doctor [repo_path].

Step 3: pipeline-trace — name the phase before guessing

Generation starts at src/functions/sequences.ts (createSequenceFn / updateSequenceFn / retryStoryboardFn) → triggerWorkflow('/storyboard', input)STORYBOARD_WORKFLOW.

Phases, in order: Verify+Prepare → Poster (non-critical) → Scene Splitting → Casting (talent ∥ location) → References & Prompts (character sheets ∥ location sheets ∥ visual prompts) → Frame Images then Motion/Music prompts (sequential since #929) → Motion + Music → Complete.

Identify the failing phase from workflowRunId / sequence_events before changing code. Phase details and per-phase inputs/outputs are in references/architecture.md.

Step 4: workflow-authoring — obey the three-place wiring and scopedDb

A new workflow is not "added" until it exists in all three places, which src/lib/workflow/wiring-consistency.test.ts enforces:

  1. wrangler.jsoncworkflows[] (and the [env.production] / [env.test] blocks — workflow config is not inherited)
  2. a re-export of the class from src/server.ts
  3. an entry in TRIGGER_TO_BINDING (src/lib/workflow/trigger-bindings.ts)

Then: extend OpenStoryWorkflowEntrypoint, implement runImpl(event, step, scopedDb), and wrap every unit of work in step.do('step-name', ...). Trigger only through triggerWorkflow() — never a raw fetch().

Three hard rules that cost the most time when broken:

  • No mid-run D1 reads. scopedDb is write-only by type. The only hatches are scopedDb.credentials.*, scopedDb.claims.*, scopedDb.liveRead.*.
  • The body replays from the top on every step callback. Steps must be idempotent; do not pass large blobs across step boundaries.
  • retries/retryDelay on triggerWorkflow() are no-ops. Retries belong on step.do() or the class.

Step 5: model-catalog — check llms.txt first, never hand-write schemas

  • LLM registry → src/lib/ai/models.config.ts (SCRIPT_ANALYSIS_MODELS)
  • Image / image-to-video / audio → src/lib/ai/models.ts
  • Motion per-model params → src/lib/motion/generated/endpoint-map.ts (generated — run bun motion:codegen, do not edit by hand)

Before changing any fal endpoint, read https://fal.ai/models/{model-path}/llms.txt — the machine-readable param spec is authoritative and more current than the HTML docs. Then bun models:check to diff the catalog. Retiring a model means marking it hidden (not selectable), not deleting it — existing rows still reference it.

Current registry snapshot and defaults: references/architecture.md.

Step 6: schema-migration — assume the CASCADE trap is live

bun db:generate      # drizzle-kit, from schema changes only
bun db:migrate:local # apply locally

Never hand-write migration SQL. Never hand-write Better Auth tables — run bun auth:generate, port the output verbatim into src/lib/db/schema/auth.ts, then bun db:generate.

The dangerous part: D1 runs multi-statement migrations inside an implicit transaction where PRAGMA foreign_keys = OFF is silently ignored, so the SQLite table-rebuild pattern fires every inbound ON DELETE CASCADE. This already destroyed prod auth tables once (#612). Prefer ALTER TABLE … RENAME/ADD/DROP COLUMN over rebuilds, and avoid ON DELETE CASCADE on FKs to user, teams, sequences. The Lefthook guard is scripts/check-migrations.ts.

Also: drizzle-kit only diffs exported tables — dropping a named export from src/lib/db/schema/index.ts makes the next db:generate emit DROP TABLE (#898).

Step 7: deploy — pick the path, then respect CLOUDFLARE_ENV

  • Zero-config: the Deploy-to-Cloudflare button clones the repo (a clone, not a fork), provisions everything in the default wrangler.jsonc block, and prompts only for BETTER_AUTH_SECRET + API_KEY_ENCRYPTION_KEY. AI keys go in afterwards via Settings → API Keys or wrangler secret put.
  • Upstream repo: Workers Builds auto-deploys main (bun run build with CLOUDFLARE_ENV=production, then bun run deploy:production).
  • Manual: bun cf:typegen && bun cf:deploy:prd.
  • PRs: GitHub Actions creates a per-PR Worker, D1, namespaced workflows, and container app; closing the PR tears them down.

A build without CLOUDFLARE_ENV=production bakes the default block (with the deliberately-invalid placeholder D1 id) and fails loudly. That placeholder is a safety feature — do not "fix" it.

Step 8: contribute — the branch name is a hard gate

Branches must be <issue-number>-feature-name (e.g. 393-improve-readme); Lefthook extracts the issue number and tags commits #<issue>, and the PR body must contain Closes #<issue>.

Before pushing:

bun lint && bun format:check && bun typecheck && bun run test

bun run test (not bun test), bun run build (not bun build), tsgo (not tsc). These three are the most repeated mistakes in the repo's own docs.

Best practices

  1. Trust the runtime parity, not your memory — local dev is real Workerd via Miniflare, so reproduce in bun dev before theorizing about a Cloudflare-only bug.
  2. Name the pipeline phase before editing code — the storyboard workflow has 7 phases with different owners; a "generation failed" report without a phase is not yet actionable.
  3. Treat scopedDb as a type-level contract, not a suggestion — if you need a read mid-run, you almost certainly need a snapshot from an earlier step.do() instead.
  4. Three-place workflow wiring or it does not existwrangler.jsonc, src/server.ts, TRIGGER_TO_BINDING. Run the wiring test.
  5. Never add "remote": true to a D1 binding and never commit a real prod database_id into the default block.
  6. Assume every migration might rebuild a table — check for CASCADE fan-out before applying anything to prod, and export first.
  7. Generation costs real moneyFAL_KEY spends per call. Use the cheapest preview model when iterating, and never loop retries on a failing generation.
  8. Cron changes must land in three places too — default block, [env.production], and the constant the scheduled() handler string- matches. A mismatch fails silently by succeeding.
  9. Regenerate, don't hand-write — motion schemas (bun motion:codegen), Better Auth tables (bun auth:generate), migrations (bun db:generate), CF types (bun cf:typegen).

References

Examples

Example 1: First run, then verify the host is actually ready

git clone https://github.com/openstory-so/openstory.git
cd openstory && bun install && bun dev
# in another shell:
bash .agent-skills/openstory/scripts/openstory.sh doctor ./openstory

doctor reports Bun/Node versions against the engine range, whether .env.local exists, and which AI keys are set — without writing anything.

Example 2: Add a new image model

  1. Read https://fal.ai/models/fal-ai/<new-model>/llms.txt
  2. Add the entry to IMAGE_MODELS in src/lib/ai/models.ts (plus an EDIT_ENDPOINTS entry if it supports editing)
  3. bun models:check to diff against the live catalog
  4. bun run test && bun typecheck

Example 3: Add a workflow without breaking the wiring test

# 1. src/lib/workflows/my-thing-workflow.ts  (extends OpenStoryWorkflowEntrypoint)
# 2. wrangler.jsonc  -> workflows[] in default, [env.production], [env.test]
# 3. src/server.ts   -> export { MyThingWorkflow }
# 4. src/lib/workflow/trigger-bindings.ts -> TRIGGER_TO_BINDING['/my-thing']
bun run test src/lib/workflow/wiring-consistency.test.ts

Example 4: Check a repo's env wiring before blaming the model

bash .agent-skills/openstory/scripts/openstory.sh env-check ./openstory

Prints which of FAL_KEY, OPENROUTER_KEY, XAI_API_KEY, BETTER_AUTH_SECRET, API_KEY_ENCRYPTION_KEY are present in .env.local (names only — never values).

Example 5: Recall the pipeline phases mid-debug

bash .agent-skills/openstory/scripts/openstory.sh phases

Use it

Copy one of these into your project. Installing also returns the manifest and these snippets.

yaml
targets:
  - https://api.opensmartroute.ai/api/v1/registry/akillness-jeo-skills-openstory/manifest   # or paste the manifest below

Manifest

An Open Capability Manifest: the router reads it to know what this does, what it costs and when to pick it.

akillness-jeo-skills-openstory.ocm.jsonjson
{
  "ocm": "1",
  "id": "akillness-jeo-skills-openstory",
  "kind": "skill",
  "name": "openstory",
  "description": "Work with OpenStory (github.com/openstory-so/openstory), the open-source AI script-to-video sequence platform built on Bun + TanStack Start + Cloudflare Workers (D1, R2, Workflows, Durable Objects) with Drizzle, Better Auth, and Fal.ai/OpenRouter models. Routes one request to one mode: run it locally (`bun install && bun dev` on Miniflare, `FAL_KEY` / `OPENROUTER_KEY`), trace the storyboard pipeline (scene split, casting, prompts, frame images, motion, music), author a Cloudflare Workflow under the three-place wiring and no-mid-run-read `scopedDb` contract, add or update an image/video/audio/LLM model, ship a safe D1 + Drizzle migration, or deploy. Use when the user mentions OpenStory or is operating this codebase. Triggers on: openstory, openstory.so, script to video, AI video sequence platform, storyboard workflow, triggerWorkflow, OpenStoryWorkflowEntrypoint, WorkflowScopedDb, IMAGE_MODELS, fal.ai model registry, D1 CASCADE data loss, flatten-migrations, deploy Cloudflare Workers video app.",
  "publisher": "akillness",
  "version": "1.0.0",
  "capabilities": {
    "domains": [
      "legal",
      "math"
    ],
    "tags": [
      "skill-md",
      "openstory",
      "ai-video",
      "script-to-video",
      "cloudflare-workers",
      "cloudflare-workflows",
      "tanstack-start",
      "bun",
      "drizzle",
      "d1"
    ],
    "languages": [
      "en"
    ]
  },
  "quality_prior": 0.6,
  "examples": [
    "Work with OpenStory (github.com/openstory-so/openstory), the open-source AI script-to-video sequence platform built on Bun + TanStack Start + Cloudflare Workers (D1, R2, Workflows, Durable Objects) with Drizzle, Better Auth, and Fal.ai/OpenRouter models. Routes one request to one mode: run it locally (`bun install && bun dev` on Miniflare, `FAL_KEY` / `OPENROUTER_KEY`), trace the storyboard pipeline (scene split, casting, prompts, frame images, motion, music), author a Cloudflare Workflow under the three-place wiring and no-mid-run-read `scopedDb` contract, add or update an image/video/audio/LLM model, ship a safe D1 + Drizzle migration, or deploy. Use when the user mentions OpenStory or is operating this codebase. Triggers on: openstory, openstory.so, script to video, AI video sequence platform, storyboard workflow, triggerWorkflow, OpenStoryWorkflowEntrypoint, WorkflowScopedDb, IMAGE_MODELS, fal.ai model registry, D1 CASCADE data loss, flatten-migrations, deploy Cloudflare Workers video app."
  ],
  "primary": false,
  "metadata": {
    "source": {
      "provider": "skills.sh",
      "repository": "https://github.com/akillness/jeo-skills",
      "path": ".agent-skills/openstory/SKILL.md",
      "ref": "HEAD",
      "url": "https://github.com/akillness/jeo-skills/blob/HEAD/.agent-skills/openstory/SKILL.md",
      "key": "akillness/jeo-skills/.agent-skills/openstory/SKILL.md"
    },
    "compatibility": "Requires Bun >= 1.3.0 < 2 and Node >= 24 < 25. Local dev needs no Docker, no external database, and no Cloudflare account — the full stack (D1, R2, Workflows, Durable Objects, email) runs in Workerd v",
    "allowed_tools": [
      "Bash",
      "Read",
      "Write",
      "Edit",
      "Glob",
      "Grep"
    ]
  },
  "instructions": "# OpenStory — AI script-to-video sequence platform\n\nOpenStory turns a written script into a styled video sequence: it splits the\nscript into scenes, casts characters and locations from reusable team\nlibraries, builds visual/motion/music prompts, renders frames through Fal.ai,\nanimates them into motion clips, scores them, and merges the result. The whole\napp is a single Cloudflare Worker (`src/server.ts`) — D1 for data, R2 for\nmedia, 33 named Cloudflare Workflows for durable generation, and a Durable\nObject for SSE progress. Local dev runs that same Workerd runtime through\nMiniflare, so there i",
  "cost": {
    "context_tokens": 3199
  }
}

Fetch it by URL: GET /api/v1/registry/akillness-jeo-skills-openstory/manifest?version=1.0.0

Reviews

Star ratings from people who tried it. One review per account; edit yours any time.

No reviews yet. Install it, try it, and be the first to rate it.