---
title: "The data root"
description: "Where workspaces, projects, brands, refs, caches, and renders live on disk."
---

All Ralphy data lives in a gitignored, hidden directory at the repo root: `.ralphy/`. Engine state sits at its top level, and **workspaces** — studio / universe / client groupings that own shared assets — nest under `workspaces/`. Two things to know up front: nothing inside a project dir is overwritten without explicit user consent (AGENTS.md invariant #14), and the directory is hidden — `ls` and `fd` skip it by default, so use `fd -H`, the `ralphy` verbs, or the Studio viewer to inspect it.

<Note>
  Pre-2026-06 roots used a visible `workspace/` tree. That layout is retired: on a legacy root every verb except `ralphy migrate` and `ralphy doctor` refuses with `E_LEGACY_LAYOUT`. Run `ralphy migrate --dry-run`, review the plan, then `ralphy migrate` — it moves everything and rewrites path strings in manifests and logs.
</Note>

## The layout

```
.ralphy/
├── registry.json                # entity registry (project-id → workspace)
├── config.json                  # CLI settings, incl. the active workspace
├── cache/
│   ├── assets/                  # ralphy-assets companion-repo cache
│   │   ├── pool/
│   │   └── required/
│   ├── library/                 # public content-library JSON cache
│   └── svg/                     # rasterized-SVG cache
├── research/                    # researcher outputs (global)
│   └── <slug>/
├── references/                  # pulled references (global)
│   └── <slug>/
└── workspaces/
    └── default/                 # one workspace = one studio / universe / client
        ├── workspace.json       # { name, slug, created, description }
        ├── shared/              # assets reused across this workspace's projects
        │   ├── brands/          # one JSON per brand
        │   ├── personas/        # one JSON per persona
        │   ├── refs/            # ref entity JSON
        │   └── cast/ music/ ... # any promoted reusable media
        ├── projects/
        │   └── coffee-shop-001/ # one project = one video
        │       ├── BRIEF.md
        │       ├── prompts.json
        │       ├── asset-manifest.json
        │       ├── STORYBOARD.md
        │       ├── postmortem/
        │       ├── artifacts/   # ALL media, by kind: images/ videos/
        │       │                # voiceover/ music/ sfx/ captions/ fonts/ refs/
        │       ├── units/       # curated deliverables
        │       ├── render/      # the final mp4 lives here
        │       └── logs/        # generations / user-prompts / user-assets .jsonl
        ├── templates/           # user-local templates
        └── batches/
```

The split to remember: `projects/<id>/` is the user-visible, append-only, irreplaceable state; everything under `cache/` is regenerable scratch managed by the CLI.

## Workspaces

A workspace groups related projects and owns a `shared/` tier for assets reused across them — cast masters, brand plates, a locked soundtrack.

```bash
ralphy workspace create fogtown --name "Fog Town"   # new grouping
ralphy workspace list                                # slug, name, project count
ralphy workspace use fogtown                         # default home for new projects
ralphy project move choose-swamp-001 fogtown         # relocate a project
```

Project ids are globally unique and resolve through `registry.json`, so every verb keeps taking a bare `<id>` — you never pass a workspace argument to `generate`, `render`, or `project show`.

Ref-style paths resolve project-first, then workspace: cwd → `<project>/` → `<project>/artifacts/refs/` → `workspaces/<ws>/shared/`. The explicit form targets the shared tier directly:

```bash
ralphy generate image --project reel-002 --slot scene-01 \
  --ref shared/cast/nurse.png    # → .ralphy/workspaces/<ws>/shared/cast/nurse.png
```

## Why the root is gitignored

It contains big binary files (mp4s, mp3s, PNGs), API responses with embedded request IDs, and per-machine paths. None of it should ride in a git history.

If you want to keep a project across machines:

- **Dump into a profile.** `ralphy profile dump <project-id>` snapshots the project into `profiles/<nick>/`, which *is* checked into the repo. Pulling a profile on another machine restores the project without clobbering local state.
- **Sync the root yourself.** rsync / Dropbox / iCloud are fine. The append-only rule means there are no concurrent-write races as long as you do not run two `ralphy` instances against the same project at once.
- **Commit the brief and the postmortem only.** Copy `BRIEF.md` and `postmortem/` into a docs folder; the heavy media stays out of git.

## Canonical vs. scratch

**Canonical: `workspaces/<ws>/projects/<id>/`.** Append-only, never overwritten. Regen creates `<slot>.v2.<ext>`, never replaces `<slot>.<ext>`. The three JSONL logs are append-only by definition — read-and-rewrite-to-tidy is a defect. Failed and rejected generations stay on disk until the user explicitly purges them (AGENTS.md invariant #14). `BRIEF.md`, `prompts.json`, `asset-manifest.json`, and `STORYBOARD.md` are updated in place, but the manifest only ever *points* at the latest version of each slot — the previous version stays on disk.

**Scratch: `cache/`.** `cache/assets/` is managed by `ralphy assets clean` and `ralphy assets pull-pool`; `cache/library/` and `cache/svg/` are short-TTL caches. Delete any of them and the CLI refetches.

Brands, personas, and refs under `workspaces/<ws>/shared/` sit in between: user-created, not auto-deleted, but not on the "never overwrite" track either. Updating a brand JSON in place is fine — there is no history.

## Wipe-safety

A clean wipe is `rm -rf .ralphy/`. After it:

- Project state is gone (unless you dumped to a profile).
- The local registry and config are gone — `registry.json` and `config.json` live at the top of `.ralphy/`.
- Brand and persona definitions are gone (short JSON — keep a backup).
- The asset cache is gone — the next `ralphy template use <slug>` re-pulls from the companion repo (SHA-256 verified).
- The **global** registry at `~/.ralphy/` is untouched — API keys and cross-checkout project mappings survive.

<Warning>
  A project dir is not safe to manually edit. The manifest, the logs, and the asset versioning all assume the CLI is the only writer. To drop a bad generation, use `ralphy project delete <id>`; never `rm` individual files inside a project.
</Warning>

## The global registry at `~/.ralphy/`

Outside the repo, Ralphy keeps a small global registry (distinct from the per-checkout `.ralphy/` data root):

```
~/.ralphy/
├── config.json        # API keys, ffmpeg path, ralphy version, defaults
├── projects.json      # known-project registry across checkouts
├── profiles/          # cached profile dumps
└── installer.lock     # release-channel pin, used by `ralphy doctor`
```

`config.json` holds the two API keys. Set them via `ralphy setup` (interactive) or by editing the file. `ralphy doctor` validates them — if a key is missing or stale, the error names the file and the field.

## Brands, personas, refs

These three live under `workspaces/<ws>/shared/`. Each is a small entity that projects can attach to.

- **Brands** (`shared/brands/<id>.json`) — logo, palette, tone, audience. Reusable across projects.
- **Personas** (`shared/personas/<id>.json`) — a recurring on-screen character; photo refs live next to the JSON.
- **Refs** (`shared/refs/<id>.json` + `.ralphy/references/<slug>/`) — entity JSON plus the pulled source video / frames / transcript written by `ralphy ref` verbs.

See [`/concepts/brands-personas`](/concepts/brands-personas) and [`/concepts/references`](/concepts/references) for the data model and the attach-to-project flow.

## The asset cache

`.ralphy/cache/assets/` is the local cache of the [`ralphy-assets`](https://github.com/alecs5am/ralphy-assets) companion repo — gameplay loops, Italian Brainrot characters, trend music. SHA-256 verified, no auth required.

```
.ralphy/cache/assets/
├── pool/
│   ├── italian-brainrot-characters/
│   └── trend-music/
└── required/
    ├── brainrot-ai-meme/
    └── soviet-nostalgic/
```

`required/` is auto-pulled on `ralphy template use <slug>` for templates that need a specific asset. `pool/` is pulled on demand with `ralphy assets pull-pool <kind>/<slug>`. See [`/concepts/asset-catalog`](/concepts/asset-catalog) for the full model.

## Related

- [Projects](/concepts/projects) — the per-project layout and lifecycle
- [Brands and personas](/concepts/brands-personas) — the identity entities under `shared/`
- [Asset catalog](/concepts/asset-catalog) — the companion-repo pool and cache
- [Generation log](/concepts/generation-log) — the JSONL schemas under `logs/`
- [CLAUDE.md](https://github.com/alecs5am/ralphy/blob/main/CLAUDE.md) — repo orientation
