> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kentron.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Observing and importing Claude Code activity

> Capture Claude Code sessions into Receipt with import and observe, and know exactly what gets captured and where it goes.

Claude Code is Anthropic's terminal coding agent. These two commands take the work you did in it and record that work in Receipt, so a session you ran in your own terminal becomes a replayable run beside the ones Receipt did itself.

`receipt import` reads a log of Claude Code activity once. `receipt observe` does the same thing and keeps following the file. Both turn each line into receipts. The ones that are uploaded land on the Sessions page as replayable runs; a local-only import stays on your machine and never appears there.

Read the warning on this page before you run either command against real work.

## Read this first

<Warning>
  **Metadata mode does not redact your prompts.**

  The `--mode metadata` default redacts a fixed list of sensitive keys from the **raw captured payload only**. The normalized receipt — the one the Sessions page reads — still contains prompt text, assistant replies, tool inputs such as the bash commands that were run, tool output such as stdout and stderr, along with the working directory and the git branch.

  Receipt's own repository documentation claims the opposite. The code and its tests do not. Do not run `receipt import` or `receipt observe` against sessions containing data you are not willing to store in Receipt.
</Warning>

<Warning>
  **Captured activity is uploaded by default.** Once you have signed in with `receipt setup`, imports and observations go to the hosted store in your Receipt workspace, not to your machine. Pass `--local-only` (or `--no-cloud`, or `--no-upload`) to keep them local.
</Warning>

## The two sources

A *source* is where the record of the session comes from. `clauden` is a companion proxy that sits in front of Claude Code and writes its own event log; `claude-code` reads the transcript files Claude Code writes for itself. Both sources are implemented, but only the second needs nothing extra: the current release does not ship the companion binary, so `clauden` works only if you supply one (see [`receipt setup` and the observer](#receipt-setup-and-the-observer)).

| Source        | What it reads                          | Default path               |
| ------------- | -------------------------------------- | -------------------------- |
| `clauden`     | The companion proxy's NDJSON event log | `~/.claudeN/events.ndjson` |
| `claude-code` | Raw Claude Code transcripts            | `~/.claude/projects`       |

For `clauden`, the default becomes the legacy text log `~/.claudeN/clauden.log` only when you also launch the companion and the resolved binary is named `clauden`. Without `--launch`, the default is always `~/.claudeN/events.ndjson`.

For `claude-code`, Receipt scans `~/.claude/projects` and takes the newest `.jsonl` file by modification time, falling back to `~/.claude/projects/latest.jsonl` when it finds none. The stream project name comes from the parent directory, and the source id is the file name with `.jsonl` stripped, which is the session UUID.

<Note>
  `claude-code` appears in **no help text**. `receipt --help` and the usage strings list only `clauden`. The source is fully implemented and validated — it is only reachable by typing it.
</Note>

Omitting the source, or naming another one, fails with the same message either way:

```
import source is required. Supported sources: clauden, claude-code
observe source is required. Supported sources: clauden, claude-code
```

## Commands

```bash theme={null}
receipt import clauden
receipt import claude-code
receipt observe clauden
receipt observe claude-code
```

`receipt import <source> [<path>]` runs once over the file. `receipt observe <source>` is the same import with follow mode forced on.

### Flags

| Flag                                            | Default                                  | Effect                                                                            |
| ----------------------------------------------- | ---------------------------------------- | --------------------------------------------------------------------------------- |
| `<path>`, `--event-log <path>`, `--path <path>` | per source, above                        | Read this file instead                                                            |
| `--mode metadata\|full`                         | `metadata`                               | Capture mode. Anything else → `--mode must be metadata or full`                   |
| `--stream <stream>`                             | `imports/<source>/<project>/<sourceId>`  | Receipt stream to write to                                                        |
| `--project <name>`, `--source-id <id>`          | derived                                  | Stream path segments, lower-cased to `[a-z0-9-]` and capped at 80 characters each |
| `--import-id <id>`                              | `clauden_<base36 time>_<8 hex>`          | Identifier for this import run                                                    |
| `--max-lines <n>`                               | unlimited                                | Stop after this many lines                                                        |
| `--follow`                                      | off on `import`, always on for `observe` | Keep reading as the file grows                                                    |
| `--poll-ms <n>`                                 | `1000`                                   | Follow poll interval, floored at 100                                              |
| `--launch`, `--launch-proxy`                    | off                                      | Spawn the companion proxy. Requires `--follow` or `observe`                       |
| `--proxy-bin <path>`, `--clauden-bin <path>`    | resolved                                 | Which companion binary to launch                                                  |
| `--port <n>`, `--no-launch`                     | —                                        | Passed through to the companion; they do nothing without `--launch`               |
| `--batch-size <n>`                              | `50`                                     | Receipts per upload request, maximum 100                                          |
| `--local-only`, `--no-cloud`, `--no-upload`     | off                                      | Do not upload; keep receipts on this machine                                      |
| `--target <name>`                               | active session                           | Which saved CLI session to upload with                                            |
| `--output-file <path>`                          | —                                        | Write the result JSON to a file                                                   |

`--launch` without `--follow` fails with `--launch requires --follow or receipt observe clauden`. Any other failure exits 1, like every other command in this CLI; see [Environment and exit codes](/cli/environment-and-exit-codes).

Both commands always emit JSON, so `--json` does nothing here:

```json theme={null}
{
  "ok": true,
  "source": "clauden",
  "importId": "...",
  "stream": "imports/clauden/...",
  "sourcePath": "...",
  "mode": "metadata",
  "follow": false,
  "storage": "cloud",
  "counts": { "lines": 0, "captured": 0, "normalized": 0, "rejected": 0, "duplicateReceipts": 0 }
}
```

When receipts were uploaded, the envelope also carries `cloud` with the gateway URL and the organization id. Read `storage` to confirm where the receipts actually went.

<Note>
  With `--output-file`, the result JSON goes to the file and stdout gets a pointer object instead — `ok`, the absolute `outputFile` and its `bytes`. Unlike `receipt tools` and `receipt mcp config`, `import` and `observe` write that file with a plain write at your default umask, not atomically and not at mode `0600`.
</Note>

## Where receipts go

There are two destinations, and the CLI picks between them for you:

1. **A saved CLI session exists** — receipts go to the hosted store in your workspace, `storage: "cloud"`.
2. **Otherwise** — receipts go to a file-backed store under `RECEIPT_DATA_DIR`, or `~/.receipt/data` when that is unset, `storage: "local"`.

Any of `--local-only`, `--no-cloud` or `--no-upload` disables the cloud path, so a signed-in machine can still keep an import to itself.

<Note>
  `ZERO_UPSTREAM_DB` is read on this path but has no effect. The released binary always forces the local store, so the third destination you may see referenced, `storage: "postgres"`, is unreachable from it — only the [developer CLI built from source](/cli/from-source/overview) can produce it.
</Note>

Uploads go to `<gatewayUrl>/api/receipt-ingest/receipts` with your session bearer token, which must carry `connect:write`. The endpoint caps a request at 2 MiB and 100 receipts, and accepts only the `imports/clauden/` and `imports/claude-code/` stream prefixes. A custom `--stream` outside those prefixes is rejected:

```
Receipt cloud ingest failed for <gatewayUrl>/api/receipt-ingest/receipts: unsupported_stream
```

## What is captured

Each transcript line produces two receipts: `import.raw_object.captured` for the raw object and `import.object.normalized` for the normalized one, or `import.object.rejected` when the line cannot be parsed. The run is bracketed by `import.batch.started` and `import.batch.completed`. Duplicates are collapsed on an event id built from the source, source id, object id and event type.

The normalized receipt carries the model, whether the call was streamed, the HTTP status, the session key, request and response byte counts, rate-limit and cooldown state, method and path, `cwd`, `gitBranch`, entrypoint, user type, prompt and request ids, version, stop reason, any error, and a `timeline`.

The timeline is the part that matters for the warning above. Each entry has a role — user, assistant, system, tool use, tool result, attachment, metadata or error — plus its text, content, token usage, tool name, tool result, and metadata including the last prompt and the permission mode.

Token counts are copied through from the transcript. Receipt does not compute a cost.

## Running it in the background

```bash theme={null}
receipt observe clauden install
receipt observe clauden start
receipt observe clauden status
receipt observe clauden stop
receipt observe clauden uninstall
```

`install` accepts `--mode`, `--event-log`, `--proxy-bin`, `--poll-ms`, `--stream`, `--receipt-bin` and `--no-start`.

This is a `clauden`-only feature. Asking for it on the other source is refused:

```
observe claude-code supports live file tailing only; use observe clauden install for proxy service install
```

To follow `claude-code` transcripts continuously, run `receipt observe claude-code` yourself and keep it running.

Only macOS and Linux are supported. Anywhere else: `Background Claude observation is currently supported on macOS and Linux.`

### Service paths

These are visible on your machine, so they are worth knowing exactly.

<Tabs>
  <Tab title="macOS">
    The launchd label is `run.beetle.clauden-observer`, at:

    ```
    ~/Library/LaunchAgents/run.beetle.clauden-observer.plist
    ```
  </Tab>

  <Tab title="Linux">
    The systemd user unit is `beetle-clauden-observer.service`, at:

    ```
    ~/.config/systemd/user/beetle-clauden-observer.service
    ```
  </Tab>
</Tabs>

Logs are written to `<dataDir>/logs/clauden-observer.out.log` and `<dataDir>/logs/clauden-observer.err.log`, where the data directory is `RECEIPT_DATA_DIR` or `~/.receipt/data`.

The installed command is:

```
<receipt> observe clauden --event-log <log> --mode <mode> --launch
```

The service runs that command and nothing else, so it uploads to the cloud store whenever a saved session exists. `install` has no `--local-only`, and the flag would not survive into the installed command: if you do not want the service uploading, do not install it.

<Note>
  The service label and unit filename use the string `beetle`, not `receipt`; Beetle is the assistant's name in the interface. Search for that string when you are looking for the service on disk.
</Note>

### `receipt setup` and the observer

[`receipt setup`](/cli/setup) installs this background observer as part of signing you in. Decline it with `--no-observer` (also spelled `--no-claude`, `--no-background` or `--skip-claude`).

The install only happens when the companion binary is on the machine, and the current release archive does not contain one, so on a stock install the step reports itself as not installed with the resolution error rather than failing the sign-in:

```
Claude observer: not installed (Unable to find the Claude observer companion binary. Install a Receipt CLI release that bundles receipt-claude-proxy, or pass --proxy-bin <path> / set RECEIPT_CLAUDE_PROXY_BIN.)
```

The CLI looks for the companion in order: `--proxy-bin`, `--clauden-bin`, `RECEIPT_CLAUDE_PROXY_BIN`, `CLAUDEN_BIN`, then `receipt-claude-proxy` next to the CLI entrypoint and next to the executable, then `clauden` in those same two places, and finally `receipt-claude-proxy` and then `clauden` on `PATH`.

## Seeing what you imported

Uploaded runs appear at `/sessions`, which reads exactly the two stream prefixes the ingest endpoint accepts. That page is not in the sidebar — it is reachable by direct URL only. With nothing imported it reads `No imported sessions yet`. A `--local-only` import never reaches it.

Next step: [look up every command, flag and exit code](/cli/command-reference).
