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

# The inbox: when a campaign needs something only you can provide

> The inbox is how a Kapso campaign asks you for a credential, access or a file, pauses, and continues the same coding session once you reply.

The inbox is how a campaign asks you for something only a person can provide, and how your reply continues the very coding session that asked. A session that needs an API key that is not in `.env`, access to a private bucket or a file that exists only on your laptop records a request, the campaign pauses and exits with `stopped_reason: waiting_for_user`, and `kapso inbox reply` resumes that session with your answer and its context intact.

Nothing polls and nothing runs in the background. Your reply is the only trigger, and a campaign never starts new work while a request is open.

## How does a session ask?

The session first proves the blocker: the session reproduces the failure with the smallest command, rules out the causes the session can fix itself, reads the repository's own docs for how the resource is normally obtained, retries anything that could be transient, and tries routes that need no person. Only then does the session call the `request_from_user` tool with everything the session needs, in one call. The call is the stop signal: the session ends its turn, the working tree is committed and pushed to the experiment branch, the node is suspended, and the campaign pauses. You read the request with `kapso inbox`, act on it, and answer with `kapso inbox reply`. The reply resumes the campaign, which continues the same session through the coding agent's own resume command with a follow-up carrying your reply and the next steps the session recorded. The session verifies for itself; if the session is still blocked, the session asks again, and the new request shows your previous reply.

```mermaid theme={null}
flowchart TD
    A["Session hits a wall it cannot fix"] --> B["Proves it is blocked: reproduces, rules out its own causes, reads the docs, retries"]
    B --> C["Calls request_from_user with key, hit, tried, fix, next_steps"]
    C --> D["Session ends; its working tree is committed and pushed to the branch"]
    D --> E["Campaign pauses: stopped_reason waiting_for_user"]
    E --> F["You: kapso inbox, then kapso inbox reply"]
    F --> G["Campaign resumes and continues the same session with your reply"]
    G --> H{"Coding agent verifies"}
    H -->|works| I["Runs the recorded next steps; the node is judged as usual"]
    H -->|still blocked| C
```

A suspended node is not judged, never becomes a parent, and does not count as an iteration. The judge only ever sees completed nodes.

## What does a request look like?

At the pause the terminal prints every open request and how to answer:

```text theme={null}
kapso build — waiting on you

  #1  env:OPENAI_API_KEY
      for    node 3 · re-rank candidates with text-embedding-3-large
      hit    openai.AuthenticationError at the embedding step — no key in the environment
      tried  OPENAI_KEY / OPENAI_API_TOKEN unset too; no .env or config in the repo; README says export OPENAI_API_KEY; two retries
      fix    add OPENAI_API_KEY=sk-... to /home/me/churn/.env
      next   embed the candidate texts, re-rank, run kapso_evaluation/evaluate.py

  reply with   kapso inbox reply "…"        # after the fix, or with what to do instead
  any time     kapso inbox /home/me/churn/campaign
```

| Row | What the row tells you |
| - | - |
| `#1` and the key | The campaign-local id you reply to, and what is missing |
| `for` | The node and the idea that needs the resource |
| `hit` | The exact failure the session reproduced |
| `tried` | What the session ruled out before asking. Judge the request from this row |
| `fix` | Where the value or grant goes. A credential goes there, never into the reply |
| `next` | What the session will do once the resource is there |

The summary block after `kapso build` says `WAITING ON YOU` instead of `COMPLETED`, and the exit code stays 0. A pause is not a failure.

## How do I answer?

Two commands:

```bash theme={null}
kapso inbox                          # what is waiting on you
kapso inbox reply 1 "added the key"  # answer request 1; the campaign resumes
```

Run inside a campaign directory, both commands act on that campaign. Run anywhere else, `kapso inbox` lists every campaign with an open request, and `kapso inbox reply` takes the campaign path first:

```bash theme={null}
kapso inbox ./campaign
kapso inbox reply ./campaign 1 "added the key"
```

The id may be left out when one request is open. An empty note means done. The `reply with` line under each listed campaign follows the same rule: outside that campaign it names the campaign's path, so the line works where it was printed.

Replying records the note and resumes the campaign in the foreground, in your terminal. Add `--detach` to walk away: the note is checked here, the campaign resumes in a session of its own, and the command returns with the log and the `kapso watch` line. Both forms work from any directory, since the launch record keeps the campaign's paths and `.env`. When a node asked for several things, the node waits until every one of its requests is answered, and the command says so:

```text theme={null}
#1 answered. #2 still open, so node 3 waits; nothing else to run.
```

The command refuses to run while a live process holds the campaign, so nothing runs twice. Two replies that start at the same moment run one resume: the second waits for the first, then has nothing to do unless the first failed.

Your reply is on disk before the resume starts. If the resume then fails or is killed, the reply stays, and `kapso inbox` shows it instead of saying nothing is waiting:

```text theme={null}
  #1  env:OPENAI_API_KEY   answered, campaign not resumed
      for    node 3 · re-rank candidates with text-embedding-3-large
      reply  'added the key'

  retry with   kapso inbox reply        # keeps your reply; a note replaces it
```

Fix what the error named and run the line it shows. A note replaces your earlier answer until a session has been given it. Once a session has been given it, a retry resends that answer and a different note is refused.

> [!WARNING]
>
> Replies are stored in plain text in `.kapso/inbox.jsonl` and handed to the
> coding agent as text. Put a credential where the `fix` row says, usually the
> `.env` the run loaded, and reply with a note. A reply shaped like a token is
> refused unless you add `--yes` at the end of the line; `Kapso.reply` refuses
> it the same way unless `allow_secret=True`, so a script or a plugin cannot
> store one by accident.

A reply that says the resource is not available is an instruction: the coding agent proceeds without the resource, and no later session in the campaign asks for that key again.

## What happens when the campaign resumes?

The campaign resumes from its checkpoint, and the session that asked is continued through the coding agent's own resume (`claude -p --resume` for Claude Code, `codex exec resume` for Codex) with a follow-up that carries your replies and the next steps the session recorded. The session's earlier context is the CLI's own transcript, so nothing is re-explained. The coding agent verifies for itself. If the coding agent is still blocked, the coding agent asks again with what the coding agent tried, and the new request shows your previous reply next to the new request.

Kapso runs no checks of its own. Nothing is resumed until you reply, and a `kapso build --resume` with a request still open pauses again without running anything. Paused time does not count against the campaign's time budget.

## What does the session keep across the pause?

Everything git can hold, plus the campaign directory and the transcript.

* **Code and every file in the session's working tree.** When the session ends after the call, the session close commits the run directory and then everything else on the node's branch, pushes the branch to the campaign repository, and only then deletes the session folder. The resumed session is a fresh checkout of that branch.
* **Datasets.** `kapso_datasets/` is tracked on the branch, since data files are committed at setup. A file you drop into the campaign's `kapso_datasets/` after launch, because a request asked for the file, is copied into the resumed session and becomes tracked when that session closes.
* **Evaluation files, run outputs, `changes.log` and the session's plan file.** On the branch.
* **The idea, the requests and the session's own next steps.** In the checkpoint node and in `.kapso/inbox.jsonl` in the campaign directory.
* **The conversation.** The coding agent's transcript on disk, under `~/.claude/projects` or `~/.codex/sessions`, keyed by the session id stored in the checkpoint node. Claude Code keeps transcripts for 30 days.

Not kept: files git ignores inside the session folder (`*.log` other than `changes.log`, `__pycache__`), anything written outside the session folder such as `/tmp`, exported environment variables, and processes the session started. The resumed session is a fresh process that loads the campaign's `.env` at start.

## Where does the pause show up?

| Surface | What the surface shows |
| - | - |
| `kapso watch ./campaign` | `WAITING ON YOU · 1 request` with the requests, readable after the process is gone |
| `.kapso/run_state.json` | `last_stop: "waiting_for_user"` on a `running` checkpoint |
| `.kapso/status.json` | `state: done` with `stopped_reason: "waiting_for_user"` and the requests |
| `on_status` | Fires once at the pause with the same payload |
| Python | `solution.stopped_reason`, `solution.requests`, `Kapso.inbox(campaign)`, `Kapso.reply(campaign, id, note)` |

A campaign started from Python with an `iteration_evaluator` callback cannot be resumed from the command line, because the callback lives in your script. `kapso inbox reply` records the note and tells you to call `build()` again with `resume=True`.

## When does the coding agent ask, and when not?

The implementation prompt sets the bar, and the `tried` row of every request shows the bar was met. A session asks only for something a person must do: installing a package, downloading public data or waiting out a rate limit is the session's own job. A request is load-bearing or the request is not made: a missing key for optional logging is dropped and mentioned in the report. Before asking, the session reproduces the failure with the smallest command, rules out every cause the session can fix itself, reads how the resource is normally obtained in the repository, retries when the failure could be transient, and tries routes that need no person. A location the repository's own README or config names for a credential is such a route, not a search. The session asks for everything the session needs in one call and does nothing after the call. The session never stubs or mocks the resource, never searches the machine for credentials, and never prints a secret's value. An idea that plans around a missing resource with an "honest zero" or a placeholder is not the goal: the session asks instead.

## How do I turn the inbox on or off?

```yaml theme={null}
defaults:
  inbox:
    enabled: true
    stop_grace_seconds: 120
    registry: "~/.kapso/campaigns.jsonl"
```

| Key | What the key does | Shipped value |
| - | - | - |
| `enabled` | Give sessions the tool and let the campaign pause | `true` |
| `stop_grace_seconds` | How long a session that asked gets to end its own turn before the adapter ends the session | `120` |
| `registry` | One line per launched campaign, so `kapso inbox` outside a campaign can list every one that waits | `~/.kapso/campaigns.jsonl` |

The block is a top-level key of the config. To turn the inbox off, put `inbox: {enabled: false}` in your override file; it is merged over the packaged block, so the other two keys keep their values. The benchmark override files ship with the inbox off. A campaign whose `node_expansion_value` is above 1 runs with the inbox off as well: a campaign with several implementation lanes cannot pause on one of them yet.

With the inbox off, sessions do not get the tool, the prompt is unchanged, no campaign pauses, and no launch record or registry line is written. The inbox block is part of the checkpoint's configuration fingerprint, so changing the block on an existing campaign blocks `--resume` for that campaign.

## What can go wrong?

* **The resume cannot start.** A moved config or evaluation directory, a missing coding agent CLI or a changed configuration raises from `kapso inbox reply`. The reply is kept and the node stays suspended. Fix the cause and retry with `kapso inbox reply`.
* **The transcript is gone.** Claude Code keeps transcripts for 30 days. If the transcript has been deleted, the reply fails with the coding agent's own error, the node stays suspended and nothing else runs. The code is still on the branch, but the context is lost: start a new campaign.
* **Kapso is killed during the continuation.** The checkpoint still marks the node suspended. `kapso inbox reply` or `kapso build --resume` continues the same session. Work the continuation had not pushed before the kill is lost; the coding agent redoes the work.
* **You supplied a wrong value.** The coding agent verifies, asks again, and the new request quotes your previous reply. Reply again after fixing the value.
* **The session asked for two things.** Answer each request; the node resumes after the last one, and every reply before that prints which requests are still open.

## Related

> [card] [Resuming runs](https://docs.leeroo.com/docs/build/resume-and-budgets.md)
>
> The checkpoint a paused campaign resumes from

> [card] [CLI reference](https://docs.leeroo.com/docs/reference/cli.md#kapso-inbox)
>
> Every form of kapso inbox

> [card] [MCP gates](https://docs.leeroo.com/docs/evolve/mcp-gates.md)
>
> The gate that carries the request\_from\_user tool

> [card] [Configuration](https://docs.leeroo.com/docs/reference/configuration.md#inbox)
>
> The inbox block and its defaults

Related pages: [Resuming runs](https://docs.leeroo.com/docs/build/resume-and-budgets.md) · [CLI reference](https://docs.leeroo.com/docs/reference/cli.md#kapso-inbox) · [Configuration](https://docs.leeroo.com/docs/reference/configuration.md) · [MCP gates](https://docs.leeroo.com/docs/evolve/mcp-gates.md) · [Execution flow](https://docs.leeroo.com/docs/evolve/execution-flow.md)

Kapso is an open-source framework by [Leeroo](https://leeroo.com) that builds software toward measurable goals through experiment campaigns. Source code: [github.com/Leeroo-AI/kapso](https://github.com/Leeroo-AI/kapso) · Install: `pip install leeroo-kapso` · Every page as plain text: [llms.txt](https://docs.leeroo.com/llms.txt).


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