.ralphy/workspaces/<ws>/projects/<id>/logs/. Three JSONL files: every model call, every user prompt, every uploaded reference. The writers live in cli/lib/gen-log.ts. This page is the schema reference: field-by-field shape, nullability, examples, and the append-only contract.
File layout
The append-only contract
AGENTS invariant #13 makes this a hard rule: the logs are append-only. Never truncate, rewrite, or filter them in place. Read-and-rewrite to “tidy” is a defect. Concretely:logGeneration(),logUserPrompt(),logUserAsset()open the file withfs.appendFile(). Neverfs.writeFile().- Failed and rejected generations stay on disk.
status: "error"rows are how cross-session reasoning works. - If the user explicitly asks to clear a project’s logs, use
ralphy project delete <id>(registry-aware) — never patch the files.
generations.jsonl
One line per model call. Written bycli/lib/gen-log.ts → logGeneration(). Read by ralphy project log <id>, ralphy project timeline <id>, and the cost-rollup verbs.
Example line
Fields
Writer signature
timestamp is auto-filled from Date.now() if you don’t pass one. Pass an explicit timestamp only when backfilling.
Lifecycle
- Written by
ralphy generate {image,video,voiceover,music,sfx,captions}automatically. Skill code never writes directly. - Written by
cli/lib/providers/media.ts → loggedFetch()for any provider call routed through that helper. - Read by
ralphy project log <id> --kind <generations|user-prompts|user-assets>and surfaces under theworking/logs-and-costsdoc page.
user-prompts.jsonl
Chronological user prompts, plus structured-override entries (e.g.--no-ref-consent reasons). Written by logUserPrompt().
Example lines
Fields
The no-ref-consent row
When the user overrides the reference-required gate (AGENTS invariant #3) via --no-ref-consent "<reason>", cli/commands/generate.ts → maybeLogNoRefConsent() writes:
stage: "no-ref-consent" rows before refusing a similar request again.
Lifecycle
- Written by the agent / playbook on every user-driven beat (intake answer, scenario feedback, regen ask).
- Written automatically by
--no-ref-consentand similar override flags. - Read by
ralphy project timeline <id>to reconstruct the user-flow.
user-assets.jsonl
References the user supplied — local files, screenshots, ref URLs. Written bylogUserAsset().
Example lines
Fields
Lifecycle
- Written when the user drops a file into the chat, runs
ralphy ref add <url-or-path>, or attaches a reference via the intake protocol. - Read by the art-director playbook to assemble the
--reflist forralphy generate image / video. - Read by
ralphy project show <id>for the references panel.
Read patterns
cli/lib/gen-log.ts → readLog<T>(projectId, name) returns the parsed array:
jq is fine:
Stability commitment
The fields above do not change without a migration. Specifically:- Renaming a field is a breaking change. Add a new field, deprecate the old in a separate PR after one major release.
- Tightening a field’s type is a breaking change. A field that was
string?cannot become required without a migration script that backfills. - Adding a new optional field is safe. Readers must tolerate unknown fields.
- Adding a new value to an enum (
provider,kind,stage,purpose) is safe — readers must tolerate unknown values.
cli/lib/gen-log.ts. Open a PR that touches the type to discuss any breaking change.
Why JSONL, not a single JSON document
Append-only is the constraint. A single JSON document would force a read-and-rewrite on every event; the JSONL shape allows naive append without parsing. The trade-off is that consumers must handle line-by-line parsing, which is fine — every read patten above does exactly that.Related
- Concepts: generation log — what the log is for, narrated.
- Working: logs and costs — how to use the data day-to-day.
- Asset manifest — the per-slot pointer table that sits next to the logs.
cli/lib/gen-log.ts— writer source.AGENTS.md— invariant #13 (append-only).