---
title: "Projects"
description: "A project is one video. This page covers the lifecycle, the on-disk layout, and the registry."
---

A project is one video. Every brief you give Ralphy becomes a project — a directory under `.ralphy/workspaces/<ws>/projects/<id>/` with a brief, prompts, assets, a render, and three append-only logs. Projects are first-class: they have a registry, a lifecycle, a versioning policy, and they are the unit the CLI mutates. Everything else (brands, personas, refs, templates) attaches to a project.

## Project IDs

A project ID is `{context}-{NNN}` — a kebab-case context tag plus a three-digit ordinal. Examples:

- `coffee-shop-001`
- `nothing-hp1-001`
- `analog-horror-fridge-001`
- `noski-people-001`
- `playdate-pixel-001`

The context tag should encode the *brief*, not the *output*. `coffee-shop-001` is a project about a coffee shop — whether the final video is 9:16 or 16:9, English or Russian, 8 seconds or 60. The ordinal increments per context: when you make a second video for the same coffee shop, the next ID is `coffee-shop-002`.

The ID lands in two places:

- The on-disk path: `.ralphy/workspaces/<ws>/projects/coffee-shop-001/`.
- The global registry: `~/.ralphy/projects.json` maps `coffee-shop-001` → `<absolute workspace path>`. This is how `ralphy project show <id>` works across multiple repo checkouts.

`ralphy new <context>` is the canonical way to create a project — it picks the next available ordinal, scaffolds the directory, and writes the registry entry.

## The on-disk layout

```
.ralphy/workspaces/<ws>/projects/coffee-shop-001/
├── BRIEF.md                # the captured brief, written during intake
├── prompts.json            # resolved per-scene prompts
├── asset-manifest.json     # slot → file pointer table
├── STORYBOARD.md            # human-readable beat list
├── POSTMORTEM.md            # legacy single-file format (old projects)
├── postmortem/              # new 6-file split (new projects)
│   ├── 01-chat-history.md
│   ├── 02-lessons.md
│   ├── 03-bugs.md
│   ├── 04-models-cost.md
│   ├── 05-workflow-fixes.md
│   └── 06-summary.md
├── artifacts/
│   ├── images/scene-01-bg.png
│   ├── images/scene-01-bg.v1.png   # auto-archived on regen
│   ├── videos/scene-01-clip.mp4
│   ├── voiceover/voiceover-en.mp3
│   ├── music/music-bed.mp3
│   └── refs/                 # user-supplied refs the agent pulled in
│       ├── product-photo.png
│       └── gameplay-loop.mp4
├── render/
│   ├── final.mp4
│   └── final.v1.mp4
└── logs/
    ├── generations.jsonl     # every model call (append-only)
    ├── user-prompts.jsonl    # every user prompt (append-only)
    └── user-assets.jsonl     # every user-uploaded ref (append-only)
```

The files break into three groups.

**Authored, edited in place.** `BRIEF.md`, `prompts.json`, `asset-manifest.json`, `STORYBOARD.md`. These describe the project's intent and pointer-state. They are updated in place by `ralphy` verbs — the manifest is a *pointer* table, so updating the pointer to point at `<slot>.v2.png` does not destroy `<slot>.v1.png` (the actual file is still on disk).

**Append-only, never rewritten.** `logs/generations.jsonl`, `logs/user-prompts.jsonl`, `logs/user-assets.jsonl`. See [`/concepts/generation-log`](/concepts/generation-log) for the schemas. These are the audit trail. Read-and-rewrite to tidy is a defect; the postmortems and cross-session memory all assume the logs are complete.

**Produced, never overwritten.** Everything under `artifacts/` and `render/`. Regenerating `scene-01-bg.png` first archives the existing file to `scene-01-bg.v1.png` (then `.v2`, `.v3`, ...) and then writes the new one. This is enforced at the file-system level by `ralphy generate` since commit `753d2f7` (2026-05-19). `--force-overwrite` opts into legacy destructive behavior.

## Lifecycle

A project moves through five stages. The agent's role at each stage is in [`docs/playbooks/`](https://github.com/alecs5am/ralphy/blob/main/docs/playbooks/README.md).

<Steps>
  <Step title="Intake">
    The user drops a brief. The agent runs [`docs/playbooks/intake.md`](https://github.com/alecs5am/ralphy/blob/main/docs/playbooks/intake.md): 3-5 clarifying questions (target language, aspect, brand, duration, hard "no"s), draft a plan in chat, wait for user "go." `BRIEF.md` is written when the user signs off. No paid generation happens before this step completes (AGENTS.md invariant — intake protocol).
  </Step>
  <Step title="Scenario">
    The scenarist playbook turns the brief into a scene-by-scene scenario — hook, beats, VO lines, on-screen text, suggested aspect, suggested register. The scenario lives in `prompts.json` and the human-readable form in `STORYBOARD.md`. The `scoreScenario` quality gate runs here; two consecutive failures stop the run.
  </Step>
  <Step title="Prompts and assets">
    The art-director playbook resolves scenes into model-specific prompts and runs the generation verbs: `ralphy generate image`, `ralphy generate video`, `ralphy generate voiceover`, `ralphy generate music`, `ralphy generate sfx`. Each produced file is a slot in `asset-manifest.json`. Each call is an entry in `generations.jsonl`. Quality gates (`scoreImage`, `scoreVideo`) run per asset.
  </Step>
  <Step title="Composition and render">
    The editor playbook authors the HyperFrames composition (`.ralphy/workspaces/<ws>/projects/<id>/index.html`) and runs `ralphy render <project>` to produce `render/final.mp4`. Captions, transitions, audio mix, and color grade are all editor-stage. A re-render archives the previous mp4 to `final.v1.mp4`.
  </Step>
  <Step title="Postmortem">
    Once the user signs off on the cut (or the project is abandoned), the `/postmortem` skill writes the 6-file split under `postmortem/`. The lessons file is what the *next* project's agent reads at session start (see [`docs/playbooks/meta.md`](https://github.com/alecs5am/ralphy/blob/main/docs/playbooks/meta.md) rule 1). This is where most of the institutional knowledge in the codebase actually accumulates.
  </Step>
</Steps>

A project does not have to walk all five stages. A quick batch project ("make 10 variants of the same hook") collapses intake into one line and skips the postmortem. A research-only project (`/researcher https://tiktok.com/...`) lands under `.ralphy/research/<slug>/` and never becomes a video at all.

## The project registry

`~/.ralphy/projects.json` is the global registry. It maps `project-id` → absolute workspace path, plus a few metadata fields (created-at, last-touched-at, status). `ralphy project list` reads this. `ralphy project show <id>` resolves the path and prints the manifest.

The registry is *additive*. Creating a new project appends to the registry. Wiping a project dir by hand does *not* clear the registry — you can have entries pointing at projects that no longer exist on disk. `ralphy project list` flags these. `ralphy project delete <id>` removes both the directory and the registry entry; that is the only safe way to forget a project.

Two consequences worth knowing:

- **You can have two ugc-cli checkouts on the same machine.** Both register projects against the same global registry. `ralphy project show coffee-shop-001` resolves to whichever checkout owns it.
- **Projects survive a workspace wipe if you dumped them to a profile.** `ralphy profile install <nick>` restores `.ralphy/workspaces/<ws>/projects/<id>/` from the profile dump under `profiles/<nick>/`.

## The append-only philosophy

Every artifact under `.ralphy/workspaces/<ws>/projects/<id>/` is append-only or version-archived. The rules (from AGENTS.md invariant #13):

- **Regen creates a new version, never overwrites.** `ralphy generate ...` against a slot that already has a file auto-archives the existing file to `<slot>.v{N}.<ext>` before writing. Pass `--force-overwrite` only when the user explicitly asks for legacy destructive behavior.
- **No `rm`, `fs.rm`, `fs.unlink`, `fs.rename`-over-existing inside a project directory** unless the user said the words "delete / remove / clean / wipe" pointing at that artifact.
- **The three JSONL logs are append-only by definition.** Never truncate, rewrite, or filter in place. Read-and-rewrite to "tidy" is a defect.
- **Failed and rejected generations stay on disk.** The gen-log + manifest reasoning across sessions depends on the failed artifacts still being there.
- **If the user wants a clean slate, they ask for it.** Use `ralphy project delete <id>` (registry-aware) or wait for explicit `rm -rf` permission scoped to a named path. Never volunteer a cleanup.

Why this matters: across 10 shipped projects' postmortems, the highest-cost recurring failure was "the agent silently overwrote a working v1 with a broken v2 and lost the good one." The CLI now prevents that at the file-system level. The asset manifest is the *pointer*; the disk holds *every* version.

See [`/concepts/generation-log`](/concepts/generation-log) for the manifest schema and the promote-a-version workflow.

## Useful verbs

```bash
ralphy new <context>                       # create a new project, picks next ordinal
ralphy project list                        # all known projects (from registry)
ralphy project show <id>                   # full project state (manifest + log summary)
ralphy project timeline <id>               # chronological log view
ralphy project log <id>                    # raw JSONL pretty-printed
ralphy project log-prompt <id> --text ...  # append a user-prompt entry
ralphy project log-asset <id> --source ... # append a user-asset entry
ralphy project delete <id>                 # registry-aware delete (asks for confirmation)
```

Full verb / flag reference at [`/cli/project-verbs`](/cli/project-verbs).

## Related

- [Workspace](/concepts/workspace) — where projects live alongside brands, refs, and the cache
- [Generation log](/concepts/generation-log) — the append-only JSONL schemas and the versioning model
- [References](/concepts/references) — when refs are required before generation
- [Templates](/concepts/templates) — `ralphy template use <slug>` scaffolds a project
- [Producer playbook](https://github.com/alecs5am/ralphy/blob/main/docs/playbooks/producer.md) — end-to-end and batch flows
