---
title: "Logs and costs"
description: "Three append-only JSONL logs. ralphy project log, timeline, jq rollups, and the auto-generated postmortem."
---

Every project keeps three append-only logs under `.ralphy/workspaces/default/projects/<id>/logs/`. Together they tell you what the model did, what you asked for, and what you uploaded — chronological, structured, never overwritten. The logs are how Ralphy reasons across sessions ("we tried this prompt three times and it kept missing the same way"), how the cost rollup gets built, and how the auto-generated postmortem knows what happened. They are also your audit trail when something looks wrong.

The contract is [AGENTS invariant #13](https://github.com/alecs5am/ralphy/blob/main/AGENTS.md): append-only. No "tidy up" passes, no in-place rewrites, no silent truncation. Reading or filtering is fine; mutating is not.

## The three log files

| File | Written by | Carries |
|---|---|---|
| `generations.jsonl` | `ralphy generate` (every sub-verb), `ralphy render`, ffmpeg recipes | Provider, model, slot, input, output, latency, cost, status |
| `user-prompts.jsonl` | `ralphy project log-prompt`, intake stages, `--no-ref-consent` override | Stage label, prompt text, timestamp, optional note |
| `user-assets.jsonl` | `ralphy project log-asset` | Kind (screenshot / photo / video / doc / ref-url), source path or URL, purpose |

Every line is one JSON object. Files grow, never shrink. The append happens via `fs.appendFile` in [`cli/lib/gen-log.ts`](https://github.com/alecs5am/ralphy/blob/main/cli/lib/gen-log.ts).

## Reading with `project log`

```bash
ralphy project log syrup-001 --type generations --limit 50
```

Returns the most recent N entries (newest last) as a JSON array. Filter by type:

- `--type generations` — model calls and renders.
- `--type user-prompts` — what you said, when, at which stage of the intake.
- `--type user-assets` — what you uploaded as a reference.
- `--type all` — all three, merged and sorted chronologically.

Pretty output is `-p`. The default JSON is what you want for piping to `jq`.

## Chronological view with `timeline`

```bash
ralphy project timeline syrup-001
```

Renders the merged log as a chronological table — who said what, when, in human-readable form. Good for reconstructing what happened in a session three days ago when you can't remember whether you regenerated scene-03 once or three times.

```text
┌─────────────────┬────────────┬──────────────────────────────────────────┐
│ timestamp       │ type       │ summary                                  │
├─────────────────┼────────────┼──────────────────────────────────────────┤
│ 14:32:11        │ user       │ brief: "selfie review, cozy autumn"      │
│ 14:32:14        │ generation │ image scene-01-bg → $0.04                │
│ 14:33:02        │ generation │ video scene-01-vid → $0.30 (kling, 5s)   │
│ 14:34:18        │ user       │ feedback: "scene-03 too slow"            │
│ 14:34:33        │ generation │ video scene-03-vid v2 → $0.42 (seedance) │
│ 14:36:01        │ render     │ final.mp4 → 4.3 MB                       │
└─────────────────┴────────────┴──────────────────────────────────────────┘
```

## Writing to the user logs

Two verbs append to `user-prompts.jsonl` and `user-assets.jsonl` from the CLI directly. Use them when the agent isn't running and you want to record context for the next session.

```bash
ralphy project log-prompt syrup-001 \
  --text "user wants the hook to feel more spontaneous, less rehearsed" \
  --stage feedback \
  --note "iteration round 2"
```

```bash
ralphy project log-asset syrup-001 \
  --kind ref-url \
  --source https://www.tiktok.com/@username/video/1234 \
  --purpose style-reference \
  --note "the energy I'm aiming for"
```

Stage labels are conventional, not enforced: `brief`, `feedback`, `decision`, `no-ref-consent`, `clarification`, etc. The intake protocol uses them to reconstruct the conversation flow.

## Cost rollups with `jq`

`generations.jsonl` carries `cost_usd` and `model` fields on every entry. Roll up by model:

```bash
ralphy project log syrup-001 --type generations --limit 500 \
  | jq -s 'group_by(.model)
           | map({ model: .[0].model,
                   calls: length,
                   total_usd: (map(.cost_usd // 0) | add) })'
```

```json
[
  { "model": "google/gemini-3-pro-image-preview", "calls": 12, "total_usd": 1.80 },
  { "model": "kwaivgi/kling-v3.0-pro", "calls": 5,  "total_usd": 1.50 },
  { "model": "elevenlabs/eleven_multilingual_v2", "calls": 4, "total_usd": 0.62 },
  { "model": "elevenlabs/music", "calls": 1, "total_usd": 0.15 },
  { "model": "hyperframes", "calls": 3, "total_usd": 0.0 }
]
```

Filter to failures:

```bash
ralphy project log syrup-001 --type generations --limit 500 \
  | jq '. | select(.status == "error")'
```

Per-slot cost:

```bash
ralphy project log syrup-001 --type generations --limit 500 \
  | jq -s 'group_by(.slot)
           | map({ slot: .[0].slot, total_usd: (map(.cost_usd // 0) | add) })'
```

For batch-level rollups, `ralphy batch show <id> --json` aggregates the same numbers across all projects in the batch.

## The auto-generated postmortem

A `POSTMORTEM.md` lands at the root of any project that the [`/postmortem`](https://github.com/alecs5am/ralphy/blob/main/.claude/skills/postmortem) skill has been run on. The skill triggers automatically on batch completion and on demand any time the user types `/postmortem` or asks for a "retro" / "lessons learned" / "debrief". For non-trivial multi-iteration sessions, the skill writes six structured files under `.ralphy/workspaces/default/projects/<id>/postmortem/`:

- Chronological chat history extracted from the log files.
- Lessons learned (with project-specific receipts).
- Ralphy CLI bug list — the raw `bunx` / `ffmpeg` / `curl` workarounds the agent had to reach for, so the verb gap can be filed.
- Model and cost rollup.
- Workflow and playbook fixes.

The postmortem is how Ralphy gets better over time. Lessons from one project show up in the playbooks; CLI gaps from one project become new verbs in `cli/commands/`.

## Cost discipline

Three rules from the playbooks worth internalizing:

- **Always cross-check [`MODELS.md`](https://github.com/alecs5am/ralphy/blob/main/MODELS.md)** before assuming a model's price. Claude's training is stale; the canonical numbers live in `MODELS.md` and the live OpenRouter catalog (`ralphy models list`).
- **`--dry-run` is free.** Every paid `generate` sub-verb supports it. Always preview before a 10-second kling call or a long ElevenLabs Music render. Detail: [Generating assets](/working/generating-assets).
- **Budget caps are the lever, not model downgrade.** [AGENTS invariant](https://github.com/alecs5am/ralphy/blob/main/AGENTS.md) bans "use a cheaper draft model" as a cost strategy — Ralphy uses the best model throughout. If you need to control cost, set a budget cap on the batch or generate fewer variants; don't drop to a worse model.

## When a log file looks weird

The append-only contract means the logs should grow monotonically. If you ever see a `generations.jsonl` that shrank between sessions, something violated the contract — either a tool wrote to the file outside the CLI, or a backup restore overwrote it. Both are bugs worth reporting. The CLI's own append path is well-tested; the failure modes are usually outside.

If you suspect drift between the manifest and the files on disk:

```bash
ralphy project verify syrup-001
```

The verify pass walks the manifest, checks every referenced file exists, checks the gen-log entries match the manifest entries, and reports drift. The verify is read-only — it won't fix anything, but it'll tell you what's broken so you can fix it by hand or by regenerating.

## Cross-project workspace stats

```bash
ralphy workspace stats
```

Aggregates across every project: total cost, total render count, disk usage, count by status. Useful for "how much did I spend this month" — pipe to `jq` and filter by `generatedAt` to scope to a date range.

## Related

- [Generation log concept](/concepts/generation-log) — the JSONL schema in concept form
- [Memory schemas](/advanced/memory-schemas) — every field on every log entry
- [Reviewing and iterating](/working/reviewing-iterating) — what the gen-log lets you reconstruct
- [Generating assets](/working/generating-assets) — `--dry-run` and cost preview
- [`MODELS.md`](https://github.com/alecs5am/ralphy/blob/main/MODELS.md) — per-model pricing
- [`/postmortem` skill](https://github.com/alecs5am/ralphy/blob/main/.claude/skills/postmortem) — the auto-postmortem flow
