# Story Adaptation Pipeline

Multi-episode microdrama production from short stories. A **story-level pipeline** (`story_pipeline.py`) sits above the existing per-episode orchestrator (`orchestrator_v5.py`).

> **For Claude**: Each story project gets a `CLAUDE.md` at its root (auto-generated by `init`). It contains project-specific rules for story adaptation. Template: [`templates/story-adaptation/CLAUDE.md.template`](../templates/story-adaptation/CLAUDE.md.template).

## Architecture

```
story_pipeline.py (story-level: S1→S5, then per-episode S6/S7)
┌──────────────────────────────────────────────────────┐
│  S1: Ingest        source text → source.txt          │
│  S2: Story Bible   characters, locations, themes     │
│  S3: Style         visual style + title artwork      │
│  S4: Characters    NanoBanana portraits → references/│
│  S5: Episodes      split story into episodes         │
│                                                      │
│  For each episode:                                   │
│    S6: Prepare     brief.txt + title card            │
│        ↓                                             │
│        orchestrator_v5.py (12 stages, 01→12)         │
│        ↓                                             │
│    S7: Review      update continuity.json            │
└──────────────────────────────────────────────────────┘
```

## Quick Start

```bash
# All commands run from scripts-v4/
cd /home/videobot/dev/microdrama-v2/scripts-v4

# 1. Initialize from URL or file
./story_pipeline.py /mnt/video/microdrama-v3/prospectors-special init \
  https://www.gutenberg.org/cache/epub/51768/pg51768.txt \
  --style "retro-futuristic cartoon, Moebius meets Archer"

# 2. Run story-level stages one by one
./story_pipeline.py /mnt/video/microdrama-v3/prospectors-special run           # S2: bible
./story_pipeline.py /mnt/video/microdrama-v3/prospectors-special run --accept  # accept → S3
./story_pipeline.py /mnt/video/microdrama-v3/prospectors-special run --accept  # accept → S4
./story_pipeline.py /mnt/video/microdrama-v3/prospectors-special run --accept  # accept → S5
./story_pipeline.py /mnt/video/microdrama-v3/prospectors-special run --accept  # accept S5

# 3. Prepare episode 1
./story_pipeline.py /mnt/video/microdrama-v3/prospectors-special prepare-episode 001

# 4. Run episode through orchestrator (12 stages)
./orchestrator_v5.py /mnt/video/microdrama-v3/prospectors-special --episode 001 run
# ... iterate through stages 01-12 with accept/refine/regenerate ...

# 5. After assembly, review episode for continuity
./story_pipeline.py /mnt/video/microdrama-v3/prospectors-special review-episode 001

# 6. Prepare and run episode 2 (now has continuity from episode 1)
./story_pipeline.py /mnt/video/microdrama-v3/prospectors-special prepare-episode 002
./orchestrator_v5.py /mnt/video/microdrama-v3/prospectors-special --episode 002 run
```

## Directory Structure

```
/mnt/video/microdrama-v3/prospectors-special/
├── source.txt                     # Original story text (from S1)
├── session.txt                    # Shared Claude session ID
├── story_pipeline.json            # Story-level pipeline state
├── style_preference.txt           # User's style preference (optional)
├── continuity.json                # Cross-episode state (updated by S7)
│
├── S1-ingest/
│   └── 001/
│       ├── source.txt             # Copy for provenance
│       └── metadata.json
│
├── S2-bible/
│   └── 001/
│       ├── story_bible.json       # Characters, locations, objects, themes
│       ├── user_message.txt
│       ├── prompt.txt
│       └── metadata.json
│
├── S3-style/
│   └── 001/
│       ├── style.json             # Visual style spec
│       ├── style_board.jpg        # Generated mood board (NanoBanana)
│       ├── title_artwork.jpg      # Series title card (NanoBanana)
│       ├── nanobanana_style_board.txt
│       ├── nanobanana_title_artwork.txt
│       └── metadata.json
│
├── S4-characters/
│   └── 001/
│       ├── characters_plan.json   # What was generated
│       ├── tom_morrison/
│       │   ├── portrait.jpg       # Character portrait (NanoBanana)
│       │   └── chat_history.json
│       ├── tom_morrison_prompt.txt
│       ├── tom_morrison_description.md
│       ├── williams4/
│       │   └── ...
│       ├── scorpion_desert.jpg    # Location reference
│       └── metadata.json
│
├── S5-episodes/
│   └── 001/
│       ├── episodes.json          # Episode breakdown
│       ├── user_message.txt
│       └── metadata.json
│
├── references/                    # Populated by S3 + S4 (standard format)
│   ├── people/
│   │   ├── tom_morrison/
│   │   │   ├── description.md     # Physical + voice description
│   │   │   └── portrait.jpg
│   │   └── williams4/
│   │       └── ...
│   ├── locations/
│   │   ├── scorpion_desert.jpg
│   │   └── goldenstone_ravine.jpg
│   └── style/
│       ├── style_board.jpg
│       └── title_artwork.jpg
│
├── 001/                           # Episode 1 (orchestrator format)
│   ├── brief.txt                  # Generated by S6
│   ├── episode_title_card.jpg     # Generated by S6
│   ├── pipeline.json              # Orchestrator state
│   ├── 01-story/
│   ├── 02-understanding/
│   ├── ... (stages 03-11)
│   └── 12-assembly/
│       └── 001/
│           └── final.mp4          # Title card prepended automatically
│
├── 002/                           # Episode 2
│   ├── brief.txt                  # Includes continuity notes from ep 1
│   └── ...
└── ...
```

## Story Pipeline Commands

### `init <source> [--style "..."]`

Initialize project and ingest source text.

- **source**: URL (Gutenberg, etc.) or local file path
- **--style**: Visual style preference (saved to `style_preference.txt`)
- Auto-runs S1 (ingest) and creates `references/` directories
- Gutenberg headers/footers are automatically stripped

```bash
# From URL
./story_pipeline.py /path/to/project init https://www.gutenberg.org/cache/epub/51768/pg51768.txt

# From local file
./story_pipeline.py /path/to/project init /path/to/story.txt --style "noir cartoon"
```

### `run`

Generate next pending story stage. Same workflow as orchestrator:

```bash
./story_pipeline.py /path/to/project run                    # Generate next stage
./story_pipeline.py /path/to/project run --accept            # Accept and advance
./story_pipeline.py /path/to/project run --accept "feedback"  # Accept with notes
./story_pipeline.py /path/to/project run --refine "feedback"  # Refine latest
./story_pipeline.py /path/to/project run --regenerate         # Fresh alternative
```

**Flow for each stage:**
1. `run` → generates, shows result + user_message.txt
2. Review output (JSON files, generated images)
3. `run --accept` → selects iteration, advances to next stage
4. Or `run --refine "make it darker"` → new iteration with feedback

### `status`

Show pipeline state and episode progress.

```bash
./story_pipeline.py /path/to/project status
```

Output:
```
Story Pipeline Status:

  S1-ingest: 001 ✓
  S2-bible: 002 ✓
  S3-style: 001 ✓
  S4-characters: 001 ✓
  S5-episodes: 001 ✓

All story stages complete. Use prepare-episode to set up episodes.

Episode Details:
  001: "Stranded" (3x3, 90s) — prepared, assembled, reviewed
  002: "The Trek" (4x4, 80s) — prepared
  003: "Goldenstone" (4x4, 80s) — not started
  004: "The Reward" (3x3, 45s) — not started
```

### `select <stage> <iteration>`

Manually select an iteration for a stage.

```bash
./story_pipeline.py /path/to/project select S2-bible 002
```

### `add-asset [--list] [TYPE ID ["description"]]`

Discover and generate reference sheets for assets that were identified during episode production but weren't part of the initial S5-assets plan. This is common when episode Stage 04 (assets identification) introduces objects, locations, or characters not covered by the story bible.

**List mode** — scan all episodes' `04-assets/` files and show assets with no reference sheet:

```bash
./story_pipeline.py /path/to/project add-asset --list
```

Output:
```
Missing asset references (not in references/):

  objects:
    sandwolves                (ep002 scenes 16) "Three lean sandwolves grouped close together, thirty feet from Morr..."
    canvas_backpack           (ep002 scenes 12-16) "Worn canvas backpack that Morrison packs with survival essentials..."
    shredded_tires            (ep002 scenes 3,6) "Two completely destroyed rear tires on the wrecked sandcar..."

  locations:
    fault_canyon_wreck        (ep002 scenes 1-6,8-13) "The bottom of a shallow fault canyon in the Scorpion Desert..."
    eddies_garage             (ep002 scenes 5-8) "Dim mechanic's garage interior visible behind Eddie on the phone..."

To create a sheet: add-asset <type> <id>
  e.g.: add-asset objects sandwolves
```

**Generate mode** — create a reference sheet for a specific asset:

```bash
# Auto-detect description from episode 04-assets files
./story_pipeline.py /path/to/project add-asset objects sandwolves

# Provide explicit description
./story_pipeline.py /path/to/project add-asset objects sandwolves "Three lean predators with yellow coats"

# With dependencies (other assets whose sheets are passed as NanoBanana references)
./story_pipeline.py /path/to/project add-asset locations fault_canyon_wreck --deps wrecked_sandcar
```

**What generate does:**

1. Finds the asset description from episode `04-assets/*/assets.json` (or uses the one you provide)
2. Calls Claude (via the story session) to write a NanoBanana prompt, following the style of existing prompts in `S5-assets/`
3. Adds the asset to `S5-assets/assets_plan.json`
4. Generates the reference sheet via NanoBanana
5. Auto-selects the iteration and copies to `references/`

After generating, the asset is available for all future episode runs — Stage 04 will find it in `references/` and Stage 05 will use it for frame consistency.

**Typical workflow after episode Stage 04:**

```bash
SP="./story_pipeline.py /mnt/video/microdrama-v3/my-story"

# See what's missing
$SP add-asset --list

# Generate sheets for important assets
$SP add-asset objects sandwolves
$SP add-asset locations fault_canyon_wreck --deps wrecked_sandcar

# Refine if needed (same commands as regular S5-assets)
$SP chat S5-assets sandwolves "make the fur more matted"
$SP regenerate S5-assets sandwolves

# Verify
$SP add-asset --list    # sandwolves no longer listed

# Re-run episode Stage 04 to pick up new references
```

### `prepare-episode <NNN> [--cli CLI]`

Run S6: Create episode directory with rich `brief.txt` and episode title card.

```bash
# Default: uses Claude with session resume
./story_pipeline.py /path/to/project prepare-episode 001

# Use alternative CLI (standalone mode, no session resume)
./story_pipeline.py /path/to/project prepare-episode 001 --cli claude-zai
./story_pipeline.py /path/to/project prepare-episode 001 --cli claude-minimax
```

**`--cli` option**: By default, uses `claude` with `--resume` to continue the story session. Alternative CLIs (`claude-zai`, `claude-minimax`) run in standalone mode with a self-contained prompt — useful when the Anthropic API content filter blocks output on certain story content. The standalone prompt includes explicit formatting instructions and requests verbatim source text inclusion.

**What it creates:**
- `{NNN}/brief.txt` — Self-contained episode brief with:
  - Story segment (actual text excerpt, verbatim)
  - Scene outline with dialogue moments and voice directions
  - Per-scene color mood mapping with hex codes from style.json
  - Character descriptions + voice signatures + portrait references
  - Visual style reminders
  - Continuity notes from previous episodes
- `{NNN}/episode_title_card.jpg` — Styled title card via NanoBanana
- `{NNN}/pipeline.json` — Empty orchestrator state
- Stage directories (01-story through 12-assembly)

### `review-episode <NNN>`

Run S7: Post-assembly review and continuity update.

```bash
./story_pipeline.py /path/to/project review-episode 001
```

**What it does:**
- Claude reviews the completed episode assembly
- Updates `continuity.json` with:
  - Character visual state (how they actually look in video)
  - Location visual details established
  - Story progress tracking
  - Quality notes (what worked, what to adjust)
- Future `prepare-episode` calls include these continuity notes

## Story-Level Stages Detail

### S1: Ingest

Downloads or copies story text. Strips Gutenberg headers/footers.

- **Input**: URL or file path
- **Output**: `source.txt` at project root

### S2: Story Bible

Claude reads the full story and produces structured analysis.

- **Input**: `source.txt` + any user references in `references/`
- **Output**: `story_bible.json`

```json
{
  "title": "Prospector's Special",
  "author": "Robert Sheckley",
  "genre": "sci-fi humor",
  "characters": [
    {
      "id": "tom_morrison",
      "name": "Tom Morrison",
      "role": "protagonist",
      "appearance": "Rugged, sun-weathered...",
      "voice": "Mid-range male, dry delivery, gets hoarser...",
      "appears_in_episodes": [1, 2, 3, 4]
    }
  ],
  "locations": [...],
  "key_objects": [...],
  "themes": [...],
  "tone": "...",
  "plot_summary": "..."
}
```

**Voice descriptions are critical** — Kling 2.6 generates dialogue in-video, so voice descriptions must be specific enough for consistency across episodes.

### S3: Style + Title Artwork

Claude defines visual direction. NanoBanana generates images.

- **Input**: `story_bible.json` + `style_preference.txt` + `references/`
- **Output**: `style.json` + `style_board.jpg` + `title_artwork.jpg`
- Images auto-copied to `references/style/`

### S4: Character Design

Claude creates NanoBanana prompts per character. NanoBanana generates portraits.

- **Input**: `story_bible.json` + `style.json` + `references/`
- **Output**: Character portraits + `description.md` per character + location images
- All auto-copied to `references/people/{id}/` and `references/locations/`

After this stage, `references/` is fully populated and compatible with the orchestrator's `reference_loader.py`.

### S5: Episode Breakdown

Claude splits the story into episodes with flexible grid/duration.

- **Input**: `source.txt` + `story_bible.json` + `style.json`
- **Output**: `episodes.json`

Each episode specifies:
- Grid layout: `"3x3"` (9 scenes) or `"4x4"` (16 scenes)
- Clip duration: `"5s"` or `"10s"`
- Scene beats with dialogue moments and voice directions
- Cliffhanger ending

### S6: Prepare Episode (per-episode)

Creates the episode's `brief.txt` — a self-contained document the orchestrator uses.

- **Input**: All story-level artifacts + `continuity.json`
- **Output**: `{NNN}/brief.txt` + `{NNN}/episode_title_card.jpg`

The brief includes the actual story text excerpt, scene outline, character voice descriptions, and continuity notes. The orchestrator's Stage 1 detects this as a "literary adaptation" brief and adapts accordingly.

### S7: Review Episode (per-episode)

Post-assembly review for cross-episode consistency.

- **Input**: Completed episode assembly + `continuity.json`
- **Output**: Updated `continuity.json`

Optional — can skip if rushing. But recommended for multi-episode consistency.

## Integration with Orchestrator

### How the orchestrator uses story pipeline output

1. **`brief.txt`** — Read by Stage 01 (story generation). The brief IS the story concept — Claude adapts it into `story.md` format with the scene breakdowns already provided.

2. **`references/`** — Standard format. The orchestrator's `reference_loader.py` finds character portraits, location images, style boards without any changes.

3. **`episode_title_card.jpg`** — Stage 12 (assembly) automatically detects this file and prepends a 3-second title card clip with slow zoom to the final video.

4. **Literary adaptation detection** — Stage 01 detects briefs from S6 by looking for markers like "Scene Outline", "Dialogue Moments", "Voice Direction". When detected, it relaxes the requirement for `brief.md` + person photos.

### Running the orchestrator for an episode

```bash
# The --episode flag tells orchestrator which directory to use as the "take"
./orchestrator_v5.py /mnt/video/microdrama-v3/prospectors-special --episode 001 run

# Same workflow as always:
./orchestrator_v5.py ... --episode 001 run --accept        # Accept stage, advance
./orchestrator_v5.py ... --episode 001 run --refine "..."   # Refine
./orchestrator_v5.py ... --episode 001 run --regenerate     # Fresh alternative
./orchestrator_v5.py ... --episode 001 run --chat "..."     # NanoBanana chat (stage 06, 07)

# Status for specific episode
./orchestrator_v5.py ... --episode 001 status
```

### Episode lifecycle

```
prepare-episode 001
    ↓
orchestrator --episode 001 run          # Stage 01: story (uses brief.txt)
orchestrator --episode 001 run --accept # → Stage 02: understanding
    ... (stages 02-08: accept/refine/regenerate) ...
orchestrator --episode 001 run --accept # → Stage 09: frames
orchestrator --episode 001 run --accept # → Stage 10: videos
orchestrator --episode 001 run --accept # → Stage 11: captions
orchestrator --episode 001 run          # Stage 12: assemble (prepends title card)
orchestrator --episode 001 run --accept # Done!
    ↓
review-episode 001
    ↓
prepare-episode 002  (now includes continuity notes from 001)
    ↓
orchestrator --episode 002 run
    ...
```

## Full Example Session

```bash
SP="./story_pipeline.py /mnt/video/microdrama-v3/prospectors-special"
OR="./orchestrator_v5.py /mnt/video/microdrama-v3/prospectors-special"

# === Story-level pipeline ===

$SP init https://www.gutenberg.org/cache/epub/51768/pg51768.txt \
  --style "retro-futuristic cartoon, Moebius meets Archer"

$SP run                              # S2: story bible
# Review S2-bible/001/story_bible.json
$SP run --accept                     # → S3

$SP run                              # S3: style + title artwork
# Review S3-style/001/style.json, style_board.jpg, title_artwork.jpg
$SP run --accept                     # → S4

$SP run                              # S4: character portraits
# Review references/people/*/portrait.jpg
$SP run --accept                     # → S5

$SP run                              # S5: episode breakdown
# Review S5-episodes/001/episodes.json
$SP run --refine "make episode 2 longer, it has the most action"
# Review S5-episodes/002/episodes.json
$SP run --accept                     # All story stages done!

# === Per-episode production ===

$SP prepare-episode 001              # S6: create brief + title card
# If content filter blocks: use --cli claude-zai or --cli claude-minimax
# $SP prepare-episode 001 --cli claude-zai
$OR --episode 001 run                # Stage 01: story
$OR --episode 001 run --accept       # → Stage 02
# ... continue through all 12 stages ...
$OR --episode 001 run                # Stage 12: assemble
$OR --episode 001 run --accept       # Episode 1 done!

$SP review-episode 001               # S7: update continuity

$SP prepare-episode 002              # S6: brief now includes continuity notes
$OR --episode 002 run                # Stage 01
# ... and so on for remaining episodes ...

# Check status anytime
$SP status
```

## Key Files Reference

| File | Location | Purpose |
|---|---|---|
| `story_pipeline.py` | `scripts-v4/` | Main story CLI |
| `story_pipeline_state.py` | `scripts-v4/lib/` | State management |
| `stage_s1_ingest.py` | `scripts-v4/story_stages/` | Download/copy source |
| `stage_s2_bible.py` | `scripts-v4/story_stages/` | Story analysis |
| `stage_s3_style.py` | `scripts-v4/story_stages/` | Style + artwork |
| `stage_s4_characters.py` | `scripts-v4/story_stages/` | Character portraits |
| `stage_s5_assets.py` | `scripts-v4/story_stages/` | Asset reference sheets + add-asset |
| `stage_s5_episodes.py` | `scripts-v4/story_stages/` | Episode splitting |
| `stage_s6_prepare.py` | `scripts-v4/story_stages/` | Episode preparation |
| `stage_s7_review.py` | `scripts-v4/story_stages/` | Post-episode review |
| `stage_s2_bible.txt` ... | `prompts/story/` | Prompt templates |
| `stage_s7_prepare_standalone.txt` | `prompts/story/` | Standalone prompt for alt CLIs |

## Troubleshooting

**"S2-bible not in inputs"** — Run story stages in order. Use `status` to see what's missing.

**"session.txt not found"** — Run `init` first to create the project.

**"source.txt not found"** — S1 didn't complete. Check `S1-ingest/001/metadata.json`.

**"Output blocked by content filtering policy"** — The Anthropic API content filter can trigger on adventure stories with peril/violence. Use `--cli claude-zai` or `--cli claude-minimax` for the `prepare-episode` stage — these alternative providers have different content policies. The standalone prompt template (`stage_s7_prepare_standalone.txt`) includes PG/12+ rating guidance and explicit formatting instructions.

**NanoBanana images not generated** — S3 and S4 continue even if NanoBanana fails (images are logged as warnings). Re-run the stage or manually generate images and place in `references/`.

**Orchestrator doesn't find references** — Check that `references/people/{id}/portrait.jpg` and `references/people/{id}/description.md` exist. S4 copies them automatically, but if S4 was skipped or failed, populate manually.

**Title card not prepended** — Stage 12 looks for `episode_title_card.jpg` in the episode directory (e.g., `001/episode_title_card.jpg`). If S6 didn't generate it, place one manually or skip.

**Continuity not applied** — `continuity.json` must exist at project root. It's created by `review-episode`. If you skip review, the next `prepare-episode` proceeds without continuity notes.
