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

# Push your traces

> Send a folder of your agent's sessions to your org from a terminal, read what each line of the push means, and follow the job that stores a large push until it is done.

This page takes you from a folder of session files on your machine to those
sessions stored in your org, with nothing but the `litmus-ai` command and an
org token. No console, and no help from us. It takes four steps, and the
same command runs them again if one is interrupted.

## Words this page uses

* **Org token**: the secret that proves a call is from your org. A `push`
  token can store evidence; `read` cannot. [Get a token](https://docs.litmus.ai/authentication.md)
  says who mints one.
* **Evidence**: anything you store in your org for Litmus to read: session
  transcripts, traces, documents. A push stores evidence.
* **Session**: one conversation between a user and your agent, with the tool
  calls it made. A transcript file holds one or many.
* **Request**: one HTTP call the command makes. A folder is sent in requests
  of up to 8 MB each, so a large export is several requests.
* **Job**: work the workspace does in the background after it has answered
  you. A large request is stored at once and read by a job; you follow the
  job until it is done. Its id starts with `job_`.
* **Already in**: a file the org already holds exactly as sent. It is counted
  and never stored twice, so running the same push again is safe.
* **Data access**: what the push shares with Litmus, declared on every push.
  The four levels are on the [CLI page](https://docs.litmus.ai/cli.md#data-access).

## 1. Install

```bash theme={null}
pip install litmus-ai-sdk
litmus-ai --version
```

The second line prints the client's version and its digest, offline. The same
file is served by your workspace at `GET /litmus.py`, so you can check one
against the other.

## 2. Say which workspace and which org

Either pin them once:

```bash theme={null}
litmus-ai init --token "$LITMUS_TOKEN" --org "$LITMUS_ORG"
```

or set the two environment variables and pass nothing: `LITMUS_TOKEN` (your
org token) and `LITMUS_ORG` (your org's tag). `LITMUS_URL` is the workspace,
and defaults to the hosted one. The variables win over the pinned values when
both are set. Nothing on this page prints a token; the command masks it in
everything it says.

## 3. Push the folder

```bash theme={null}
litmus-ai push ./sessions --org "$LITMUS_ORG" --surface my-agent --data-access verbatim
```

* `./sessions` is a folder (or a `.zip`, `.tar`, `.tar.gz`). Every file in it
  is read: session transcripts and trace files as sessions, `.md`, `.txt`,
  `.pdf`, `.pptx` and `.docx` as documents. A file of a kind Litmus does not
  read is listed as refused, by name; hidden files and a Mac folder's
  metadata are skipped.
* `--surface` names the system your agent drives. With it, the push starts
  the pipeline on that system once, after the last request.
* `--data-access` says what the push shares. Leave it off on a terminal and
  the command asks, with the four levels numbered; in CI or a script a push
  without it is refused before anything is read or sent.
* `--request-bytes <n>` changes how much one request holds (default 8 MB).
  You will not normally need it; the command comes down on its own when a
  request does not get through.

### What the lines mean

The command says what it is doing before each request, not after:

```text theme={null}
request 1 of 6 · 540 files · 8.0 MB → sending
  job_3f9c2a1b7d04 · planned 120 / 540 · stored 118 · 14 s
  job_3f9c2a1b7d04 · planned 540 / 540 · stored 536 · 61 s
  job_3f9c2a1b7d04 · done · 62 s
request 2 of 6 · 538 files · 8.0 MB → sending
```

* `request k of n · files · size → sending` is one request leaving your
  machine. A small push is one request and is answered in it.
* A line starting `job_` means the workspace stored that request whole and is
  reading it in the background. `planned` is how many of the request's files
  it has read so far, `stored` how many it has kept (new, or replacing an
  earlier version of the same session), and the last number is how long you
  have waited. The line is printed each time the numbers move, every two
  seconds at most, until `done`.
* If a request does not get through (the gateway answers 502 or 504, or the
  connection drops), the command says so and sends the same files again in
  two requests of half the size. It never sends a file the job had already
  stored. If the smaller request fails too, the push stops and prints the
  request it stopped at and the line that resumes it:

```text theme={null}
push: stopped at request 3 of 7: the gateway answered 504 at its minute, twice.
Nothing sent so far is lost — 212 of this request's files are in your org already.
The same command resumes at request 3: the workspace answers 'already in' for
every file it holds and stores none twice.
```

Run the same command again. Files already in are counted as such and
skipped by the workspace, and the push carries on from where it stopped.

### The summary

After the last request, one line per outcome and reason — its count and up to
three example paths — and then the totals, in the workspace's own words:

```text theme={null}
  accepted · 3,221 files · e.g. agents/ops-bot/sessions/2026-10-28-a.jsonl, agents/ops-bot/sessions/2026-10-28-b.jsonl, agents/ops-bot/sessions/2026-10-29-a.jsonl
  already in · 2 files · agents/ops-bot/sessions/2026-10-27-a.jsonl, agents/ops-bot/sessions/2026-10-27-b.jsonl
  skipped · 1 file · "it is the session index." · agents/ops-bot/sessions/sessions.json
  skipped · 1 file · toolmap.json
3,221 sessions accepted, 2 already in, 2 skipped
  3,221 sessions, 18,940 turns, 41,207 tool calls
  formats: 3,221 OpenClaw sessions
  tool map: toolmap.json (14 rules) — 39,880 of 41,207 calls reach the new surface
    unmapped (no counterpart): slack_react
    undecided (no rule, or outside a split's cases): web_fetch
  org: my-org
  pipeline: started (job_8a1d0e4c5b27)
```

* **accepted / replaced / already in / refused / skipped** are the workspace's
  outcomes for each file. *Replaced* means the org held an earlier version of
  that session and now holds this one; the earlier one is kept, not counted.
  Files that met the same outcome for the same reason share one line, so a
  reason thousands of files share is read once, not thousands of times; pass
  `--verbose` to print every file's outcome on its own line
  (`<path>: refused — <reason>`) when you need to find one file.
* **formats** counts the sessions by the format each file was read as. Only
  the formats that arrived are named.
* **tool map** appears when the push held session transcripts and a
  `toolmap.json`: how many of the recorded tool calls map onto the system
  you named, and the tool names left *unmapped* (no counterpart on it) or
  *undecided* (no rule names them). Those two lists are what to settle next;
  they hold tool names only, never a line of a transcript.
* **pipeline** is the job the push started on your system, when it started
  one.

## 4. Follow a job from Claude

Every `job_` id above is a job you can read from anywhere a tool reaches the
workspace. From Claude, attached as [Attach Claude](https://docs.litmus.ai/mcp/attach-claude.md)
shows, ask:

> Where is job `job_3f9c2a1b7d04`?

Claude calls `job_status` with `{"job_id": "job_3f9c2a1b7d04"}` and reads
the same record the command was printing from. While the job runs, `tally`
holds `files_done` of `files`, what is accepted, replaced, already in,
refused and skipped so far, and each landed file's name and outcome; `step`
says which of its three steps (open, ingest, finish) it is on. Once it is
done, `result` holds the whole answer the summary above was printed from.
Over HTTP the same record is `GET /v0/jobs/{job_id}` on the
[Runs](https://docs.litmus.ai/reference/runs.md) page.

## If something is refused

* **A whole folder is refused before anything is sent** when one of its files
  holds something shaped like a secret. The message names the file and the
  count. Re-run with `--allow-secrets` if they are not secrets.
* **One file is refused** when it is larger than one request holds, or of a
  kind Litmus does not read; the summary names it with the reason, and the
  rest of the push is unaffected.
* **A whole request is refused** (the answer is `422`) when an archive holds a
  path that leaves it, a link, or more than 2,000 entries. Nothing of it is
  stored; fix the archive and push again.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.