# Project export: Scroll-Stack

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: OpenAI Build Week
- Tagline: Turn books into stories you can read and watch.
- Devpost: https://devpost.com/software/book-reel
- GitHub: https://github.com/Legend101Zz/ScrollStack
- Video: https://www.youtube.com/embed/f0d_nqc5OVc?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 2 GitHub contributor(s) — Utkarsh Maurya (27 commits), Mrigesh Thakur (14 commits)

## Devpost submission (written by the team)

### Overview

Project Story

### Inspiration

We didn't start with a noble idea about education. We started with a confession. One of us had a shelf. Real books, bought with real intent, all of them stopped somewhere around page 40. The other had a screen-time report that said four hours a day on reels. Same person, roughly. Same evening, usually. The book lost every single night — not because it was worse, but because it asked for something the phone never asks for: a running start. Reading is a cold engine. You have to rebuild the world in your head every time you open the cover — who these people are, where we left off, why any of it matters. Reels ask for nothing. You arrive mid-thought, you're already inside, and the next one is already loading. It isn't a discipline problem. It's an interface problem. One medium front-loads all the cost and back-loads all the payoff, and the other does the exact opposite. Then we noticed the thing we both actually did finish: manga. Hundreds of pages, in one sitting, no willpower involved. Manga is not a lighter version of a book. It's a book that solved the cold-start problem — panels give you the world instantly, faces carry the emotion, and your eye pulls you down the page faster than you decided to go. We had never once "tried" to read manga. We just read it. So the question stopped being how do we make people read more and became something much more fun: What if the book you never finished came to you as the thing you always finish? That's ScrollStack. You hand it a PDF — a novel, a biography, a dense thing your friend keeps recommending — and it comes back as a manga edition you can actually sit and read. Chapters, recurring characters that look like themselves on page 3 and page 30, panels that hold a beat, pages that turn. And the parts that hit hardest get cut into short vertical reels, so the same scroll reflex that used to cost you an evening now spends it on something that stays with you. We were deliberate about one thing: this is not a study tool. No quizzes, no streaks, no progress bar guilting you. It's entertainment that happens to be made of good books. If it feels like homework, we built the wrong thing.

### What it does

You give ScrollStack a book and choose how much of it you want. It produces a manga edition — ordered, composed, lettered pages you read like any manga — and stores it in your library so you can reopen it, keep going, or ask for more. Under the surface the product runs one honest pipeline: The surfaces a reader actually touches: /books/new — drop in a PDF, watch the stages move. /library — every manga edition you've made, reopenable. /manga/{edition} — the reader itself. Reels — vertical cuts derived from the manga you already accepted, played through a real Remotion player and exportable as deterministic H.264/AAC MP4. Two product rules we refused to bend: Source-grounded, not vibes-grounded. Every panel traces back to specific source units in the actual PDF. The system holds a versioned context pack so a character can't quietly become someone else forty pages later. Editions are immutable. When you accept an edition, it's frozen — pages, panel images, hashes, lineage, accepted and rejected attempts, and the exact cost. What you read today is byte-identical to what you read next month.

### How we built it

Shape of the system. A FastAPI + Pydantic control plane owns truth and contracts. MongoDB (via Beanie) owns durable state — projects, runs, artifacts, memory. Celery + Redis own the workflow and retry lifecycle, because a manga run is a long chain of steps where any one of them can fail and none of them should take the whole run down. The frontend is Next.js 15 / React 19 with Tailwind and shared design tokens. Deterministic video is Remotion, run headless in a dedicated renderer package. One seam, generated in both directions. The single cross-language boundary is packages/contracts/. Pydantic models are canonical; JSON Schema and TypeScript types are generated from them and committed with the source change. Generated files are never hand-edited. That one rule is why two people could build the manga lane and the reel lane in parallel worktrees without a week of integration pain — the reel player consumed manga-manifest.v1 and reel-spec.v1 off fixtures long before the backend could emit real ones. Three boundaries carry the whole product: Determinism as a feature, not a nicety. Generation is expensive and non-deterministic; reading must not be. So the model touches the run only inside bounded creative sessions, and everything downstream — composition, lettering, page assembly, reel rendering — is deterministic given accepted artifacts. Re-run a run ID and you get the same pages back, no new spend. Cost as a first-class model. Image generation dominates. If a page holds $n_p$ panels and $r$ is the fraction of attempts we reject on quality, the expected image spend for a $P$-page edition is $$ C \;=\; c_{\text{img}} \sum_{p=1}^{P} \frac{n_p}{1 - r} $$ which makes the two levers obvious: cut panels per page, or cut the rejection rate. Rejections are the silent budget killer — in our demo edition, accepted panels cost \( \$0.4319757 \) while total image spend including three rejected attempts was \( \$0.549321 \). That's \( \approx 21\% \) burned on output nobody ever sees. Every rejected attempt is stored with its receipt precisely so that number stays visible instead of hiding inside a total. The demo edition, honestly. For the hackathon slice we ran pages 1–15 of a real PDF through the pipeline with zero new text-model calls — reusing an accepted context pack — producing an immutable edition of five composed 1200×1800 pages from ten accepted panel images, one accepted character reference, and full lineage. One rejected panel was retried once; no accepted panel was ever regenerated. How the two of us worked. Hard ownership lines, written down before any code: one lane owns the backend, contracts, manga surfaces, and the shared visual system; the other owns the Remotion renderer, reel components, and reel routes. Separate git worktrees driven by separate Codex sessions, PR-only into a shared dev, and a standing rule that no PR is complete without its contract fixture and visual evidence. Every handoff in NEXT_SESSION.md states what passed, what's still broken, and who moves next. The full agent workflow is documented in CODEX_USAGE.md.

### Challenges we ran into

Character continuity is the whole ballgame. A model asked twice for "the same person" gives you two people. Manga dies instantly if the protagonist's face drifts between pages — the reader doesn't consciously notice, they just stop believing it. We solved it by treating a character as an accepted, hashed reference artifact that every later panel is anchored to, rather than as a sentence in a prompt. Text inside generated images. We explicitly instructed no embedded text and got back a panel with an English heading burned into the artwork, plus pseudo-lettering scribbled around the speech balloons. That output was technically a beautiful monochrome manga render and we rejected it anyway, because lettering has to come from the deterministic renderer or it can never be edited, translated, or trusted. We still ship a known limitation here: OCR finds no letters in accepted image layers, but some accepted panels contain empty balloon shapes the model drew unprompted. Real words are renderer output; those hollow shapes are on the list. Front matter is not a story. Our parser stores one source unit per PDF page, and the first fifteen pages of a real book are title pages, copyright, and a table of contents. Source-correct, dramatically worthless. It taught us that selection — which part of the book — is a product decision, not a preprocessing detail. Latency vs. iteration speed. Mid-build, the text model was slow enough that a single full run ate the feedback loop. Rather than fake it, we cut scope on purpose: prioritize a small page range, reuse accepted upstream artifacts, spend zero new text tokens, and get something real on screen. Constrain the run, not the honesty. Two people, one repo, no stomping. Avoided almost entirely by the generated contract seam and worktree isolation. The one place we did collide was NEXT_SESSION.md — and since each lane appended its own dated section, even that merged cleanly. Infrastructure honesty. A Mongo 7 archive is currently being served by Mongo 8.2.3. It works. We wrote the cross-major restore warning into the handoff anyway, because a demo that succeeds doesn't retroactively make the setup correct.

### Accomplishments we're proud of

A real, immutable manga edition generated from a real PDF — five composed pages, ten accepted panels, complete hashes, lineage, receipts, and exact cost. A single generated contract seam that let two people build in parallel from day one and merge additively, with no breaking contract change to date. Determinism end to end — the same run ID reproduces the same pages, and ReelSpec drives both the live player and the exported MP4 from one source. Rejections are visible. Failed attempts and their costs are stored, not swallowed. We can tell you exactly what the waste was. We shipped what actually worked. Nothing is marked complete without its fixture and visual evidence — a rule we enforced against ourselves more than once.

### What we learned

The bottleneck was never comprehension — it was cold start. Books ask you to rebuild a world before they give you anything. Panels hand you the world free. That one asymmetry explains the entire shelf of unfinished books. Consistency beats beauty. A merely-good panel of a character who looks right lands harder than a gorgeous panel of a stranger. Readers forgive rough art; they do not forgive a face that changed. Push non-determinism to the edges. Let the model be creative inside bounded sessions, then make every downstream step deterministic. It's the difference between a demo and a product. Generated contracts are a collaboration technology. They weren't a typing convenience — they were the reason two lanes never blocked each other. Cutting scope honestly beats faking scope. "Pages 1–15, zero new text calls, here's the receipt" got us further than a broad claim we couldn't stand behind.

### What's next

for ScrollStack Kill the empty balloons and finish the lettering pass so every visible word is deterministic renderer output. Smarter source selection — skip front matter, find the scenes worth drawing instead of walking the PDF linearly. The full reel loop in production, with signed media delivery, thumbnails, and persisted render receipts. Reader-side continuity — progress that survives a reload, a library that remembers where the good part was. Director's cut. Let a reader reorder panels, retitle a chapter, add a line of commentary, and share their own edition of a book. The scroll becomes authorship. Cost transparency for readers — show what an edition cost to make. Nobody else does this. We think people would rather know.

## README (from the GitHub repository)

# ScrollStack

ScrollStack turns a selected part of a book into a source-grounded manga, then
derives short vertical reels from the accepted manga. The product is designed
as entertainment-first media: readers see chapters, characters, continuity,
and cuts rather than internal generation terminology.

## Architecture

The implementation follows [`technical-imp.md`](technical-imp.md):

```text
PDF and selected source units
  -> versioned context pack
  -> typed manga direction and composition artifacts
  -> RenderedPage and MangaManifest
  -> ReelSpec
  -> deterministic manga and Remotion renderers
```

- MongoDB owns durable project, memory, run, and artifact truth.
- Celery owns the workflow and retry lifecycle.
- Pi runs bounded creative sessions behind one internal adapter.
- Pydantic models generate JSON Schema and TypeScript contracts.
- `RenderedPage` is the manga reader boundary.
- `MangaManifest` is the manga-to-reel handoff.
- `ReelSpec` drives both live playback and deterministic export.

Architecture decisions live in [`docs/adr/`](docs/adr/README.md).

## Repository lanes

- Mrigesh owns `backend/`, canonical contracts and fixtures, manga surfaces,
  global styling, root workspace configuration, and the shared visual system.
- Utkarsh owns `reel-renderer/`, `packages/reel-components/`, reel routes, and
  `frontend/components/ReelFeed/`.

See [`AGENTS.md`](AGENTS.md) before changing shared paths.

## Local development

Requirements:

- Node.js 22.19 or later
- pnpm 10.15.1 through Corepack
- Python 3.12 and `uv`
- Docker with Compose
- `zsh` for the `start.sh` and `stop.sh` helper scripts
- Chromium and FFmpeg/ffprobe for local Remotion export smoke tests

Install JavaScript dependencies once:

```bash
corepack enable
corepack prepare pnpm@10.15.1 --activate
corepack pnpm install
```

### Full Docker stack

Run the local app stack:

```bash
cp .env.example .env
./start.sh
```

`./start.sh` creates `.env` from `.env.example` if it is missing, then runs:

```bash
docker compose --profile agent up -d
```

The core services expose:

- Frontend: `http://localhost:3000`
- Backend: `http://localhost:8000`
- MongoDB: `mongodb://localhost:27017`
- Redis: `redis://localhost:6379`

Stop the stack with:

```bash
./stop.sh
```

The `agent` profile is enabled by `start.sh`. The `reels` Compose profile is
reserved for the render-worker container; it should not be treated as ready
until `reel-renderer/Dockerfile` exists.

Important local flags in `.env.example`:

```env
AGENTIC_MANGA_PIPELINE_V1=true
REELS_ENABLED=false
REEL_EXPORT_ENABLED=false
```

Reel playback/export is disabled by default for the full app until the backend
produces accepted `MangaManifest` and `ReelSpec` records.

### Frontend-only development

Use this when working on UI against the configured backend URL:

```bash
corepack pnpm --filter @scrollstack/frontend dev
```

### Reel fixture export

The reel renderer can export the committed preview fixture without a backend.
Use absolute output paths:

```bash
SCROLLSTACK_BROWSER_EXECUTABLE=/usr/bin/chromium \
corepack pnpm --filter @scrollstack/reel-renderer render -- --still --frame 0 --out /tmp/scrollstack-reel.png

SCROLLSTACK_BROWSER_EXECUTABLE=/usr/bin/chromium \
corepack pnpm --filter @scrollstack/reel-renderer render -- --out /tmp/scrollstack-reel.mp4
```

`SCROLLSTACK_BROWSER_EXECUTABLE` is optional if Remotion can find a supported
browser automatically. `ffprobe` must be available on `PATH` for media
verification.

## Verification

```bash
corepack pnpm check
docker compose --env-file .env.example config --quiet
zsh -n start.sh
zsh -n stop.sh
git diff --check
```

Lane-specific checks:

```bash
(cd backend && uv run pytest tests/ -q)
corepack pnpm --filter @scrollstack/frontend typecheck
corepack pnpm --filter @scrollstack/frontend build
corepack pnpm --filter @scrollstack/reel-renderer typecheck
corepack pnpm --filter @scrollstack/reel-renderer test
```

## AI-assisted engineering provenance

ScrollStack was built with OpenAI Codex and GPT-5.6 used as engineering
assistants during planning, implementation, review, and documentation. Their
role was to accelerate repository setup, coordinate the two-contributor work
split, draft implementation plans, inspect diffs, and produce scoped code
changes under human direction.

The project keeps AI assistance separate from product runtime behavior:

- Codex helped maintain the collaboration guide in [`AGENTS.md`](AGENTS.md),
  plan ownership boundaries, and keep Mrigesh's core/manga lane separate from
  Utkarsh's reel-rendering lane.
- GPT-5.6-assisted coding was used for targeted implementation work such as
  contract-aware reel playback, deterministic Remotion rendering, progress
  integration, tests, and handoff notes.
- Runtime creative generation is intentionally constrained by typed artifacts.
  Models may propose manga or reel data, but the application accepts only
  schema-validated outputs such as `RenderedPage`, `MangaManifest`, and
  `ReelSpec`.
- Deterministic renderers, tests, and visual evidence are used to verify the
  accepted artifacts instead of trusting model output directly.

Human contributors remain responsible for product decisions, final code review,
accepted contracts, submitted PRs, and release readiness. Commit history, PR
descriptions, test output, and evidence files are the source of truth for what
was implemented and validated.

## Build Week notes

ScrollStack is a new repository created for OpenAI Build Week. Before
submission this section should include the primary feedback session ID, golden
demo source license, exact setup instructions, and final validation evidence.


## Detected evidence (automated analysis)

Indexed codebase: 272 recognized source files, 1856 KB.
- CSS (language) — detected in the code
- FastAPI (technology) — detected in the code
- JavaScript (language) — detected in the code
- Next.js (technology) — detected in the code
- Python (language) — detected in the code
- React (technology) — detected in the code
- Tailwind CSS (technology) — detected in the code
- TypeScript (language) — detected in the code
- AI coding agent: Codex — evidence: config files committed to the repository

## Codebase structure (from repository index)

### Files (120 of 376)

```
.dockerignore
.editorconfig
.env.example
.gitignore
AGENTS.md
apps/agent-worker/Dockerfile
apps/agent-worker/package.json
apps/agent-worker/README.md
apps/agent-worker/src/config.ts
apps/agent-worker/src/index.ts
apps/agent-worker/src/run-registry.ts
apps/agent-worker/src/security/auth.ts
apps/agent-worker/src/server.ts
apps/agent-worker/src/skills/book-canon/SKILL.md
apps/agent-worker/src/skills/load.ts
apps/agent-worker/src/skills/manga-composition/references/asset-reuse.md
apps/agent-worker/src/skills/manga-composition/references/bubbles-and-narration.md
apps/agent-worker/src/skills/manga-composition/references/panel-rhythm.md
apps/agent-worker/src/skills/manga-composition/SKILL.md
apps/agent-worker/src/skills/manga-direction/references/manga-grammar.md
apps/agent-worker/src/skills/manga-direction/references/manga-plan-v1.md
apps/agent-worker/src/skills/manga-direction/references/source-grounding.md
apps/agent-worker/src/skills/manga-direction/SKILL.md
apps/agent-worker/src/skills/manga-page-writing/SKILL.md
apps/agent-worker/src/skills/manga-thumbnail/SKILL.md
apps/agent-worker/src/skills/reel-direction/references/manga-camera-language.md
apps/agent-worker/src/skills/reel-direction/references/pacing.md
apps/agent-worker/src/skills/reel-direction/references/reel-safe-zones.md
apps/agent-worker/src/skills/reel-direction/SKILL.md
apps/agent-worker/src/tools/domain-tool-broker.ts
apps/agent-worker/test/config.test.ts
apps/agent-worker/test/domain-tool-broker.test.ts
apps/agent-worker/test/server.test.ts
apps/agent-worker/tsconfig.json
artifacts/README.md
backend/.gitignore
backend/.python-version
backend/app/__init__.py
backend/app/api/__init__.py
backend/app/api/books.py
backend/app/api/control_plane.py
backend/app/api/internal_tools.py
backend/app/api/reels.py
backend/app/container.py
backend/app/contracts/__init__.py
backend/app/contracts/artifacts.py
backend/app/contracts/base.py
backend/app/contracts/context.py
backend/app/contracts/manga.py
backend/app/contracts/reel_delivery.py
backend/app/contracts/reel.py
backend/app/contracts/registry.py
backend/app/contracts/runs.py
backend/app/contracts/source.py
backend/app/main.py
backend/app/persistence/__init__.py
backend/app/persistence/documents.py
backend/app/persistence/mongo.py
backend/app/persistence/protocols.py
backend/app/persistence/repositories.py
backend/app/services/__init__.py
backend/app/services/agent_worker.py
backend/app/services/context_compiler.py
backend/app/services/deterministic_manga_demo.py
backend/app/services/domain_tools.py
backend/app/services/errors.py
backend/app/services/generation_runs.py
backend/app/services/generation_workflow.py
backend/app/services/hackathon_manga.py
backend/app/services/hashing.py
backend/app/services/image_generation.py
backend/app/services/manga_editions.py
backend/app/services/manga_layout.py
backend/app/services/manga_page_planning.py
backend/app/services/manga_production.py
backend/app/services/manga_reader.py
backend/app/services/manga_validation.py
backend/app/services/memory.py
backend/app/services/page_domain_tools.py
backend/app/services/pdf_ingestion.py
backend/app/services/projects.py
backend/app/services/reels.py
backend/app/services/scopes.py
backend/app/services/source_units.py
backend/app/worker/__init__.py
backend/app/worker/authority.py
backend/app/worker/celery_app.py
backend/app/worker/tasks.py
backend/Dockerfile
backend/pyproject.toml
backend/scripts/export_contracts.py
backend/scripts/persist_phase1_proof.py
backend/scripts/run_phase2_image_preview.py
backend/scripts/verify_mongo_continuity.py
backend/tests/test_app.py
backend/tests/test_contracts.py
backend/tests/test_control_plane_api.py
backend/tests/test_durable_context.py
backend/tests/test_manga_layout.py
backend/tests/test_manga_page_planning.py
backend/tests/test_reel_api.py
backend/tests/test_vertical_slice.py
backend/uv.lock
docker-compose.yml
docs/adr/001-model-provider-policy.md
docs/adr/002-mongodb-durable-authority.md
docs/adr/003-pi-agent-runtime-boundary.md
docs/adr/004-agent-tool-allowlists.md
docs/adr/005-artifact-contract-boundaries.md
docs/adr/006-remotion-rendering.md
docs/adr/007-contract-generation.md
docs/adr/008-worker-isolation.md
docs/adr/009-manga-page-dsl-v2.md
docs/adr/README.md
docs/assets/last-observatory.md
docs/evidence/deterministic-demo-run_7f884b611dfcbc2cd0922137/README.md
docs/evidence/mrigesh-core-golden-path-2026-07-21.md
docs/evidence/mrigesh-core-vertical-slice-2026-07-20.md
frontend/.eslintignore
frontend/.eslintrc.json
[256 more files omitted for size]
```

### Dependencies

- apps/agent-worker/package.json: @scrollstack/agent-runtime@workspace:*, @scrollstack/contracts@workspace:*, @sinclair/typebox@0.34.41, @types/node@24.10.1, fastify@5.8.5, tsx@4.21.0, typescript@5.9.3, vitest@4.0.16
- backend/pyproject.toml: beanie@==2.0.0, celery[redis]@==5.5.3, fastapi@==0.116.1, httpx@==0.28.1, pydantic@==2.11.7, pymupdf@==1.24.14, python-multipart@==0.0.12, uvicorn[standard]@==0.35.0
- frontend/package.json: @phosphor-icons/react@^2.1.10, @radix-ui/react-slot@^1.2.3, @radix-ui/react-toggle-group@^1.1.10, @remotion/player@4.0.493, @remotion/preload@4.0.493, @scrollstack/contracts@workspace:*, @scrollstack/design-tokens@workspace:*, @scrollstack/reel-components@workspace:*, @types/node@^22.17.2, @types/react@^19.1.10, @types/react-dom@^19.1.7, autoprefixer@^10.4.21, eslint@^8.57.1, eslint-config-next@^15.5.0, motion@^12.23.12, next@^15.5.0, postcss@^8.5.6, react@^19.1.1, react-dom@^19.1.1, tailwindcss@^3.4.17, typescript@^5.9.2, zustand@^5.0.8
- packages/agent-runtime/package.json: @earendil-works/pi-coding-agent@0.80.10, @scrollstack/contracts@workspace:*, @types/node@24.10.1, typebox@1.1.38, typescript@5.9.3, vitest@4.0.16
- packages/contracts/package.json: @types/node@22.15.30, ajv@8.18.0, ajv-formats@3.0.1, json-schema-to-typescript@15.0.4, typescript@5.8.3, vitest@3.2.4
- packages/reel-components/package.json: @remotion/media@4.0.493, @scrollstack/contracts@workspace:*, @scrollstack/design-tokens@workspace:*, @types/react@^19.1.10, @types/react-dom@^19.1.7, react@^19.1.1, react@^19.1.1, react-dom@^19.1.1, react-dom@^19.1.1, remotion@4.0.493, typescript@^5.9.2, vitest@3.2.4
- reel-renderer/package.json: @remotion/bundler@4.0.493, @remotion/renderer@4.0.493, @scrollstack/reel-components@workspace:*, @types/node@^22.17.2, @types/react@^19.1.10, @types/react-dom@^19.1.7, react@^19.1.1, react-dom@^19.1.1, remotion@4.0.493, tsx@4.21.0, typescript@^5.9.2, vitest@3.2.4

### Recent commits (newest first)

- docs: clarify local development guide
- docs: document AI-assisted engineering provenance
- chore(artifacts): add rendered reel and poster for review
- spike(reel-renderer): prove MangaManifest is a projection, not new authoring
- Merge pull request #10 from Legend101Zz/codex/mrigesh-core-vertical-slice
- merge: resolve main integration for manga demo
- feat: ship deterministic manga demo slice
- feat: further improve manga and fix issues
- feat(reel-renderer): generate reel panel art through OpenRouter
- feat(reel-components): render panels as inked manga rather than flat colour
- docs: add fresh book run handoff
- feat: add manga page planning pipeline
- fix(reel-components): correct reel layout and follow Remotion markup rules
- release: promote dev to main — manga golden path, reel derivation, receipts, and audio
- merge: reel spec derivation, render receipts, and audio into dev
- feat(reel-components): add synthesized music beds with a volume envelope
- feat(reel-components): add a reviewed CC0 audio kit and deterministic SFX cues
- feat(reel-renderer): produce a RenderReceipt for every MP4 export
- feat(reel-components): derive ReelSpecs from a MangaManifest
- merge: integrate Mrigesh persisted manga golden path into dev

## Key source files (fetched from GitHub, selected and truncated for size)

### AGENTS.md

```markdown
# ScrollStack collaboration guide

Read `technical-imp.md` before making architecture or ownership decisions. It
is the project blueprint; this file defines how two contributors work from it
without overwriting each other.

## Ownership

### Mrigesh — core, manga, and visual system

Mrigesh owns the control plane, canonical contracts, manga workflow, and shared
visual language. This includes:

- `backend/`, including Pydantic models, API, persistence, context, artifacts,
  ingestion, and manga pipeline work;
- `packages/contracts/` schema sources and generated contract artifacts;
- `packages/fixtures/` canonical cross-language fixtures;
- `apps/agent-worker/` and `packages/agent-runtime/`, including the pinned Pi
  adapter, production skills, internal worker API, and domain tool broker;
- `packages/design-tokens/`, including the framework-neutral tokens consumed by
  both the frontend and the reel lane;
- global theme and layout files, including Tailwind configuration and global
  CSS;
- root workspace/package configuration and `docker-compose.yml`.

### Utkarsh — Remotion and reel UX

Utkarsh owns the deterministic reel renderer and the isolated
reel user experience. This includes:

- `reel-renderer/`;
- `packages/reel-components/`;
- `frontend/app/**/reels/`;
- `frontend/components/ReelFeed/`;
- reel-specific tests and visual evidence.

The reel player must consume the shared design tokens and generated contract
types. Do not change the global theme or create local `any`-based copies of
`ReelSpec`, `MangaManifest`, or other shared models.

## Shared integration seam

`packages/contracts/` and the Pydantic schema exports are the only
cross-language data seam.

- Mrigesh owns canonical Pydantic model changes and commits regenerated JSON
  Schema and TypeScript artifacts with the source change.
- Generated files are never hand-edited.
- Utkarsh requests missing data through an issue or PR comment
  that states the field, consumer, and a fixture example.
- Both contributors must review a breaking contract change before it merges.
- Root package files, `pnpm-workspace.yaml`, Docker Compose, shared generated
  contracts, global styling, and common layouts require explicit agreement
  before editing.

## Git and worktree workflow

- `main` is the protected release branch. Do not develop or integrate directly
  on it.
- `dev` is the shared integration branch. Merge reviewed feature branches into
  `dev`, then promote `dev` to `main` through one final PR when both owners are
  ready.
- Use one worktree per lane:
  - Mrigesh: `codex/manga-context-control-plane` in `../ScrollStack-manga`.
  - Reel player: `codex/pi-reel-player` in `../ScrollStack-reel`.
- Keep uncommitted work inside your own worktree. Rebase on current `main`
  only when preparing the final `dev` to `main` promotion. Feature branches
  should start from and rebase on current `dev` before opening their PRs.
- Merge feature work into `dev` through focused PRs only. Resolve conflicts in
  f
[truncated — 1384 more characters]
```

### MRIGESH_CORE_VISUAL_HANDOFF.md

```markdown
# Mrigesh core and visual system handoff

**Snapshot:** 2026-07-19

**Repository:** `Legend101Zz/ScrollStack`

**Branch:** `codex/manga-context-control-plane`

**Worktree:** `/Volumes/Mrigesh SSD/Scrollhack/ScrollStack-manga`

**Implementation baseline:** `82cf96c` (`docs: align ownership with reel-only lane`)

**Architecture source of truth:** [`technical-imp.md`](technical-imp.md)

This document is the execution handoff for Mrigesh's lane. It records what was
built, what is still only a scaffold, and the order in which the next session
should continue. It does not assign work in Utkarsh's reel-owned paths.

## Ownership boundary

Mrigesh owns:

- `backend/`;
- `apps/agent-worker/` and `packages/agent-runtime/`;
- `packages/contracts/` and `packages/fixtures/`;
- `packages/design-tokens/`;
- manga and shared frontend surfaces;
- global styling, root workspace files, and Docker Compose.

Utkarsh owns:

- `reel-renderer/`;
- `packages/reel-components/`;
- `frontend/app/**/reels/`;
- `frontend/components/ReelFeed/`;
- reel-specific rendering, playback, gesture, and visual evidence.

Do not edit Utkarsh's paths from this branch. Cross-lane work must happen
through the generated v1 contracts, canonical fixtures, and shared design
tokens.

## What was completed

### 1. Repository and architecture foundation

- Created the pnpm, `uv`, Next.js, FastAPI, Celery, MongoDB, Redis, and Docker
  Compose workspace foundation.
- Added ADR-001 through ADR-008 for the provider, persistence, Pi runtime,
  security, contract, Remotion, generation, and worker-isolation decisions.
- Preserved the technical document's hard boundaries: Mongo is durable truth,
  Celery owns workflows, Pi receives bounded context, models emit typed
  artifacts, and renderers stay deterministic.
- Added contributor ownership and worktree rules in [`AGENTS.md`](AGENTS.md).

### 2. Canonical contracts and fixtures

- Added Pydantic v1 contracts for source, scope, context, run, artifact, manga,
  and reel boundaries.
- Added deterministic JSON Schema export and generated TypeScript types.
- Added Ajv validators and 17 canonical cross-language fixtures.
- Established `RenderedPage` as the reader payload, `MangaManifest` as the
  manga-to-reel handoff, and strict `ReelSpec` as the reel boundary.
- Added rejection coverage for unknown scene types, extra props, arbitrary
  paths, and unsafe URLs.

### 3. Durable context and control-plane foundation

- Added Beanie documents and indexes for source units, scopes, manga projects,
  memory snapshots, artifacts, generation runs, and stage runs.
- Added Mongo-backed and deterministic in-memory repository adapters.
- Added bounded context compilation, source selection, optimistic memory-delta
  merging, hashing, idempotent run creation, cancellation, and artifact
  listing.
- Added versioned scope and generation-run API surfaces.
- Added a Celery workflow authority and dispatcher shell.

### 4. Safe Pi worker foundation

- Pinned the Pi coding-agent de
[truncated — 10560 more characters]
```

### package.json

```
{
  "name": "scrollstack",
  "version": "0.1.0",
  "private": true,
  "packageManager": "pnpm@10.15.1",
  "engines": {
    "node": ">=22.19.0"
  },
  "pnpm": {
    "overrides": {
      "postcss": "8.5.10"
    }
  },
  "scripts": {
    "build": "corepack pnpm -r --if-present build",
    "test": "corepack pnpm -r --if-present test",
    "typecheck": "corepack pnpm -r --if-present typecheck",
    "contracts:generate": "corepack pnpm --filter @scrollstack/contracts generate",
    "contracts:test": "corepack pnpm --filter @scrollstack/contracts test",
    "frontend:build": "corepack pnpm --filter @scrollstack/frontend build",
    "check": "corepack pnpm contracts:test && corepack pnpm typecheck && corepack pnpm test"
  }
}

```

### docker-compose.yml

```yaml
name: scrollstack

services:
  mongo:
    image: mongo:7
    restart: unless-stopped
    ports:
      - "27017:27017"
    volumes:
      - mongo_data:/data/db
    healthcheck:
      test: ["CMD", "mongosh", "--quiet", "--eval", "db.adminCommand('ping').ok"]
      interval: 5s
      timeout: 3s
      retries: 20

  redis:
    image: redis:7-alpine
    restart: unless-stopped
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
      timeout: 3s
      retries: 20

  backend:
    build:
      context: ./backend
    restart: unless-stopped
    environment:
      MONGODB_URI: ${MONGODB_URI:-mongodb://mongo:27017/scrollstack}
      REDIS_URL: ${REDIS_URL:-redis://redis:6379/0}
      MEDIA_ROOT: /data/media
      AGENT_WORKER_URL: ${AGENT_WORKER_URL:-http://agent_worker:8788}
      AGENT_WORKER_TOKEN: ${AGENT_WORKER_TOKEN:-replace-with-a-long-random-token}
      DOMAIN_TOOL_BROKER_TOKEN: ${DOMAIN_TOOL_BROKER_TOKEN:-replace-with-a-third-long-random-token}
      AGENTIC_MANGA_PIPELINE_V1: ${AGENTIC_MANGA_PIPELINE_V1:-false}
      REELS_ENABLED: ${REELS_ENABLED:-false}
      REEL_EXPORT_ENABLED: ${REEL_EXPORT_ENABLED:-false}
      ALLOW_LLM_CODEGEN: "false"
    ports:
      - "8000:8000"
    healthcheck:
      test: ["CMD", "uv", "run", "--no-dev", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/readyz', timeout=2)"]
      interval: 5s
      timeout: 3s
      retries: 20
    volumes:
      - media_data:/data/media
    depends_on:
      mongo:
        condition: service_healthy
      redis:
        condition: service_healthy

  celery_worker:
    build:
      context: ./backend
    restart: unless-stopped
    command: ["uv", "run", "--no-dev", "celery", "-A", "app.worker.celery_app", "worker", "--loglevel=INFO", "--concurrency=1"]
    environment:
      MONGODB_URI: ${MONGODB_URI:-mongodb://mongo:27017/scrollstack}
      REDIS_URL: ${REDIS_URL:-redis://redis:6379/0}
      MEDIA_ROOT: /data/media
      AGENT_WORKER_URL: ${AGENT_WORKER_URL:-http://agent_worker:8788}
      AGENT_WORKER_TOKEN: ${AGENT_WORKER_TOKEN:-replace-with-a-long-random-token}
      AGENTIC_MANGA_PIPELINE_V1: ${AGENTIC_MANGA_PIPELINE_V1:-false}
      OPENROUTER_API_KEY: ${OPENROUTER_API_KEY:-}
      IMAGE_MODEL: ${IMAGE_MODEL:-google/gemini-2.5-flash-image}
      ALLOW_LLM_CODEGEN: "false"
    volumes:
      - media_data:/data/media
    depends_on:
      mongo:
        condition: service_healthy
      redis:
        condition: service_healthy

  agent_worker:
    profiles: ["agent"]
    build:
      context: .
      dockerfile: apps/agent-worker/Dockerfile
    restart: unless-stopped
    environment:
      AGENT_WORKER_TOKEN: ${AGENT_WORKER_TOKEN:-replace-with-a-long-random-token}
      AGENT_PROVIDER: ${AGENT_PROVIDER:-minimax}
      AGENT_MODEL: ${AGENT_MODEL:-MiniMax-M2.7-highspeed}
      AGENT_MODEL_API_KEY_ENV: ${AGENT_MODEL_API_KEY_ENV:-MINIMAX_API_KEY}
      AGENT_MAX_CONCURRENCY: ${AGENT_MAX_CONCURRENCY:-2}
      AGENT_SESSION_DIR: /data/agent-sessions
      DOMAIN_TOOL_BROKER_URL: ${DOMAIN_TOOL_BROKER_URL:-http://backend:8000}
      DOMAIN_TOOL_BROKER_TOKEN: ${DOMAIN_TOOL_BROKER_TOKEN:-replace-with-a-third-long-random-token}
      MINIMAX_API_KEY: ${MINIMAX_API_KEY:-}
      ALLOW_LLM_CODEGEN: "false"
    volumes:
      - agent_sessions:/data/agent-sessions
    depends_on:
      backend:
        condition: service_healthy
      redis:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:8788/readyz').then((r)=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"]
      interval: 5s
      timeout: 3s
      retries: 20

  reel_render_worker:
    profiles: ["reels"]
    build:
      context: ./reel-renderer
    restart: unless-stopped
    environment:
      RENDER_OUTPUT_DIR: /data/render-output
      ALLOW_LLM_CODEGEN: "false"
    volumes:
      - media_data:/data/media:ro
      - render_output:/data/render-output

  frontend:
    build:
      context: .
      dockerfile: frontend/Dockerfile
      args:
        NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-http://localhost:8000}
    restart: unless-stopped
    environment:
      NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-http://localhost:8000}
      INTERNAL_API_URL: ${INTERNAL_API_URL:-http://backend:8000}
    ports:
      - "3000:3000"
    depends_on:
      backend:
        condition: service_healthy

volumes:
  agent_sessions:
  media_data:
  mongo_data:
  redis_data:
  render_output:

```

### backend/Dockerfile

```
FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim

ENV PYTHONDONTWRITEBYTECODE=1 \
    PYTHONUNBUFFERED=1 \
    UV_COMPILE_BYTECODE=1 \
    UV_LINK_MODE=copy

WORKDIR /app

COPY pyproject.toml uv.lock ./
RUN uv sync --frozen --no-dev

COPY app ./app

EXPOSE 8000
CMD ["uv", "run", "--no-dev", "uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]

```

### reel-renderer/package.json

```
{
  "name": "@scrollstack/reel-renderer",
  "version": "0.1.0",
  "private": true,
  "type": "module",
  "engines": {
    "node": ">=22.19.0"
  },
  "exports": {
    ".": {
      "types": "./src/index.ts",
      "import": "./src/index.ts"
    }
  },
  "scripts": {
    "render": "tsx src/cli.ts",
    "test": "vitest run",
    "typecheck": "tsc --noEmit",
    "generate-panels": "tsx scripts/generate-panels.ts",
    "spike:manifest": "tsx scripts/manifest-bridge-spike.ts"
  },
  "dependencies": {
    "@remotion/bundler": "4.0.493",
    "@remotion/renderer": "4.0.493",
    "@scrollstack/reel-components": "workspace:*",
    "react": "^19.1.1",
    "react-dom": "^19.1.1",
    "remotion": "4.0.493"
  },
  "devDependencies": {
    "@types/node": "^22.17.2",
    "@types/react": "^19.1.10",
    "@types/react-dom": "^19.1.7",
    "tsx": "4.21.0",
    "typescript": "^5.9.2",
    "vitest": "3.2.4"
  }
}

```

### frontend/package.json

```
{
  "name": "@scrollstack/frontend",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "eslint . --ext .js,.mjs,.ts,.tsx",
    "typecheck": "tsc --noEmit"
  },
  "dependencies": {
    "@phosphor-icons/react": "^2.1.10",
    "@radix-ui/react-slot": "^1.2.3",
    "@radix-ui/react-toggle-group": "^1.1.10",
    "@remotion/player": "4.0.493",
    "@remotion/preload": "4.0.493",
    "@scrollstack/contracts": "workspace:*",
    "@scrollstack/design-tokens": "workspace:*",
    "@scrollstack/reel-components": "workspace:*",
    "motion": "^12.23.12",
    "next": "^15.5.0",
    "react": "^19.1.1",
    "react-dom": "^19.1.1",
    "zustand": "^5.0.8"
  },
  "devDependencies": {
    "@types/node": "^22.17.2",
    "@types/react": "^19.1.10",
    "@types/react-dom": "^19.1.7",
    "autoprefixer": "^10.4.21",
    "eslint": "^8.57.1",
    "eslint-config-next": "^15.5.0",
    "postcss": "^8.5.6",
    "tailwindcss": "^3.4.17",
    "typescript": "^5.9.2"
  }
}

```

### backend/pyproject.toml

```
[project]
name = "scrollstack-backend"
version = "0.1.0"
description = "ScrollStack FastAPI control plane and canonical contracts"
requires-python = ">=3.12,<3.13"
dependencies = [
  "beanie==2.0.0",
  "celery[redis]==5.5.3",
  "fastapi==0.116.1",
  "httpx==0.28.1",
  "pydantic==2.11.7",
  "pymupdf==1.24.14",
  "python-multipart==0.0.12",
  "uvicorn[standard]==0.35.0",
]

[dependency-groups]
dev = [
  "mypy==1.17.1",
  "pytest==8.4.1",
  "ruff==0.12.7",
]

[tool.pytest.ini_options]
addopts = "-ra"
pythonpath = ["."]
testpaths = ["tests"]

[tool.ruff]
line-length = 100
target-version = "py312"
extend-exclude = ["app/contracts", "scripts", "tests/test_contracts.py"]

[tool.ruff.lint]
select = ["E", "F", "I", "B", "ASYNC"]

[tool.mypy]
python_version = "3.12"
plugins = ["pydantic.mypy"]
strict = true
exclude = ["scripts/"]

[[tool.mypy.overrides]]
module = ["celery", "celery.*"]
ignore_missing_imports = true

[[tool.mypy.overrides]]
module = ["pymupdf"]
ignore_missing_imports = true

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.hatch.build.targets.wheel]
packages = ["app"]

```

### frontend/Dockerfile

```
FROM node:22.19.0-bookworm-slim AS build

WORKDIR /app
RUN corepack enable && corepack prepare pnpm@10.15.1 --activate

COPY package.json pnpm-lock.yaml pnpm-workspace.yaml tsconfig.base.json ./
COPY frontend/package.json frontend/package.json
COPY packages/contracts/package.json packages/contracts/package.json
COPY packages/design-tokens/package.json packages/design-tokens/package.json
COPY apps/agent-worker/package.json apps/agent-worker/package.json
COPY packages/agent-runtime/package.json packages/agent-runtime/package.json

RUN corepack pnpm install --frozen-lockfile

COPY frontend frontend
COPY packages/contracts packages/contracts
COPY packages/design-tokens packages/design-tokens

ARG NEXT_PUBLIC_API_URL=http://localhost:8000
ENV NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL}
ENV NEXT_TELEMETRY_DISABLED=1

RUN corepack pnpm --filter @scrollstack/contracts build \
    && corepack pnpm --filter @scrollstack/frontend build

FROM node:22.19.0-bookworm-slim AS runtime

ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
WORKDIR /app
RUN corepack enable && corepack prepare pnpm@10.15.1 --activate

COPY --from=build --chown=node:node /app /app

USER node
EXPOSE 3000
CMD ["corepack", "pnpm", "--filter", "@scrollstack/frontend", "start"]

```

### packages/design-tokens/package.json

```
{
  "name": "@scrollstack/design-tokens",
  "version": "0.1.0",
  "private": true,
  "type": "module",
  "exports": {
    ".": {
      "types": "./src/index.d.ts",
      "default": "./src/index.js"
    },
    "./tokens.json": "./src/tokens.json",
    "./theme.css": "./src/theme.css",
    "./tailwind-preset": "./src/tailwind-preset.cjs"
  },
  "files": [
    "src"
  ]
}

```

[261 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]