A project is a folder. You make one with npm create vfrey@beta my-channel, open it in your coding agent, and ask for videos. The folder tells the agent what to do, holds the videos under readable names, and has its own dashboard. A project is explicit: it is the folder that holds a vfrey.json file. A command run in some other folder does not quietly make a database there.

What is in it

vfrey.json looks like { "version": 1, "name": "my-channel", "id": "<uuid>" }. The id lets a dashboard prove which project it serves. Commit vfrey.json. The .gitignore leaves out node_modules/, .vfrey/, and videos/. The skill copies in the project match the version of the package the project installed, so they are never older than it. Because the instruction files and skills are already there, an agent started in the folder needs nothing else. See Your agent. npx @vfrey/vfrey@beta init does the same scaffold in the folder you are in. Run it again to repair a project: it writes what is missing and keeps what exists. create-vfrey is a thin wrapper around it that also runs npm install and vfrey doctor.

Found like git finds .git

Every command starts in the folder you run it from and walks up to the first folder that holds vfrey.json. That folder is the project root, and its data folder is <root>/.vfrey/. So you can run npx vfrey from my-channel/scenes/octopus/ and it works on my-channel.

Which engine renders

Each run picks an engine in this order: --engine, then the series, then the project’s vfrey.json (npx vfrey init --engine ENGINE_ID records it), then the machine default. See Engines.

Where the data goes

The data folder is chosen in this order:
  1. DATA_DIR, if set.
  2. VFREY_HOME, if set.
  3. The nearest project’s .vfrey/ folder.
  4. The machine desk, ~/.vfrey.
The environment variables win, so tests and power users keep control. Outside a project, commands still work, on the machine desk. A command that makes or lists videos (tick, worker, render, videos) prints one line on stderr:
With DATA_DIR or VFREY_HOME set, the line is not printed, because the data is not on ~/.vfrey. In --json output, tick, videos, and open report project as { name, root }, or null when no project decided the folder.

Readable videos

In a project, a finished video is videos/YYYY-MM-DD <title>.mp4, with the transcript beside it as .txt. The title is made safe for a file name: no / : \ * ? " < > |, at most 80 characters. If the name is taken, it becomes ... (2).mp4. The run id stays in the database and the dashboard, not in the file name. Do not rename or move a video by hand, because vfrey tracks its path. Outside a project, the machine desk keeps renders/JOB_ID.mp4 as before. npx vfrey videos lists them either way.

One dashboard per project

npx vfrey open reuses this project’s dashboard when it is running. If not, it starts one in the background, waits until it answers, opens your browser, and prints the URL. Run it again and you get the same dashboard, not a second server. The dashboard outlives the agent session. Its log is .vfrey/dashboard.log. Two projects run two dashboards on two ports, and each page header shows its project’s name (the machine desk shows “Machine desk”). A dashboard counts as this project’s only when it answers GET /api/state with this project’s id, so open never lands you on another project’s dashboard. See Local desk.

The machine index and vfrey projects

~/.vfrey/projects.json lists every project on the machine: id, name, root, and when it was last used. init and create-vfrey add to it, and any command that resolves a project refreshes its entry. It is a convenience only. A project’s data never depends on it.
prints one line per project with its last video and whether its dashboard is up. A project whose folder is gone shows as missing. npx vfrey projects --prune drops those, and --json prints it for a machine. Outside a project, npx vfrey open does not guess. If the machine desk has no videos and projects exist, it lists them and tells you to cd into one.

Bring your ~/.vfrey along

If you made videos before projects, import them:
or, in an existing folder, npx @vfrey/vfrey@beta init --from ~/.vfrey. It copies the database (run ids kept), the renders as readable files in videos/ with their transcripts, and the scene copies. Stored paths are rewritten. The source is not changed, and a source that another vfrey process is writing to is refused. Run it again and it adds nothing.

Symlinked folders

vfrey compares folders by their real path, with symlinks resolved. A project reached through a symlink is the same project: discovery, the data folder, the machine index (projects.json lists it once, by its real root), and the dashboard check all agree. So cd into a symlink to a project and run npx vfrey as usual.

Move or rename the folder

Moving or renaming a project folder is fine. A project’s video paths are stored relative to the project root, and discovery finds the marker wherever the folder now is. The machine index updates the next time you run a command inside it. Until then npx vfrey projects shows the old path as missing.