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

# lua build-session

> Build an agent with Claude in the cloud from your terminal - chat, try the session's version, release it, and answer approvals, secrets and files

*Requires lua-cli 3.59.0 or later.*

`lua build-session` opens a live build session from your terminal: Claude works on your agent in the cloud while you chat with it. These are the same sessions the Lua desktop app opens, so you can start a session in one and carry on in the other. You can chat, send files, try the session's version of the agent, release it, and answer whatever the session asks of you, such as an approval or a secret.

> [!NOTE]
>
> Build sessions must be on for your organization. They are on for every organization from 25 October 2026. An organization that turns off its `buildSessions.enabled` feature has opted out; there, every command fails with `build_sessions_disabled` and does nothing else.
>
> `lua --help` does not list `build-session` unless `LUA_BUILD_SESSIONS_ENABLED=true` is set in your own environment. The value must be exactly `true`. The commands work either way, and `lua build-session --help` always prints their help.

## Synopsis

```bash theme={null}
lua build-session                                  # chat: the current session, or pick one
lua build-session start [--agent <agentId>] [--fleet] [--resume] [--base live|latest_saved]
                        [--no-wait] [--timeout <s>] [--no-chat]
lua build-session chat [--agent <agentId>] [--auto-save <dir>] [--verbose]
lua build-session attach [sessionId] [--after <n>] [--until-idle] [--timeout <s>] [--verbose]
lua build-session send "<text>" [--file <path>]... [--interrupt] [--no-follow] [--timeout <s>] [--verbose]
lua build-session stop
lua build-session try "<message>" [--live] [--agent <agentId>] [--thread <threadId>]
lua build-session release [--summary <text>] [--approve] [--wait] [--timeout <s>]
lua build-session end [sessionId] [--save]
lua build-session remove [sessionId] [--save]       # alias: rm
lua build-session kill [sessionId] [--reason <text>]
lua build-session list [--all]
lua build-session use <sessionId>
lua build-session resume [sessionId] [--no-chat] [--timeout <s>] [--verbose]
lua build-session approvals [--all-sessions]
lua build-session approve <id>
lua build-session deny <id> [--reason <text>]
lua build-session secret <requestId> [--decline] [--from-stdin]
lua build-session files
lua build-session download [attachmentId] [--all] [-o <dir>] [-f]
lua build-session status [sessionId] [--agent <agentId>]
```

Every command also takes `--json`, and every command that works on one session takes `--session <sessionId>`.

## Description

A build session belongs to one agent and to the person who started it. One agent has at most one open session at a time. A session id looks like `bs_<uuid>`.

### The current session

After `start`, `attach`, `chat`, `use` or `resume`, the CLI remembers the session as the current one, so the other commands need no id. It keeps it in `~/.lua-cli/build-sessions.json`, which every terminal of your user account on this computer shares. A command picks its session in this order:

1. the id given as an argument or with `--session <sessionId>`;
2. `LUA_BUILD_SESSION_ID` in the environment;
3. the current session the CLI remembers.

To work on two sessions side by side, set `LUA_BUILD_SESSION_ID` in each terminal.

`end` and `kill` without an id let you pick one of your open sessions when you run them in a terminal, with the current one listed first.

### Sessions and their states

| State | Meaning |
| - | - |
| `starting` | The session is getting ready. `start` waits for it, up to `--timeout`. |
| `active` | Claude is working on a turn. |
| `idle` | Ready for your next message. |
| `parked` | Put aside with its work kept. `chat` and `resume` bring it back. |
| `ended` | Ended with `end` or `remove`. |
| `failed` | The session stopped on an error. |
| `killed` | Stopped hard with `kill`, or by an administrator. |

An ended, failed or killed session can't be resumed; start a new one. Work you did not save stays in the session's checkpoints for 7 days. There is no delete: ended sessions are removed automatically after the retention period.

## Chat

In a terminal, `lua build-session` with no command, `lua build-session start`, `chat` and `resume` open a chat once the session is ready. Type a message and press Enter. Replies stream in as they are written and render as Markdown. A message you type while a turn runs is queued, and the chat shows its place, for example `queued #1`.

When the chat opens on a session that already has history, it does not replay it. It prints a short summary of where you left off instead, then only what happens next.

| Key | What it does |
| - | - |
| `Ctrl-C` during a turn | Stops the turn. Press it again to send the stop again; it never leaves the chat. |
| `Ctrl-C` twice at an empty prompt | Leaves the chat. The session keeps running. |
| `Ctrl-D` | Leaves the chat. The session keeps running. |

Re-enter the chat later with `lua build-session chat`.

### Slash commands

| Command | What it does |
| - | - |
| `/file <path> [message]` | Attach a file and send it, with the message if you give one. |
| `/paste [message]` | Attach the image on the clipboard, such as a screenshot copied with `Cmd-Ctrl-Shift-4`. macOS only. |
| `/detach-files` | Drop the files waiting for your next message. |
| `/interrupt <message>` | Stop the running turn and run this message now. `Ctrl-C` stops a turn without a new message. |
| `/try <message>` | Try the session's version of the agent. See [`try`](#try). |
| `/release [summary]` | Build the release candidate. See [`release`](#release). |
| `/status` | The session: its state, its base version, credits spent today and in total, and what is staged for testing. |
| `/diff` | What the session changed against the version it started from. |
| `/end [--save]` | End the session. `--save` keeps the work. |
| `/approvals` | What this session waits on you for. |
| `/approve <id>`, `/deny <id> [reason]` | Approve or decline an action request or a release card. |
| `/secret <id> [--decline]` | Type a secret the session asked for. The input is hidden. |
| `/files` | The session's files, yours and the ones Claude shared, numbered. |
| `/save <n\|id\|all> [dir]` | Download a file by its number from `/files`, by its id, or all of them. It never overwrites a file. |
| `/sessions` | Your open build sessions, in every organization and agent. |
| `/switch` | Pick another of your sessions. This one keeps running. |
| `/new` | Start a session on another agent. This one keeps running. |
| `/detach`, `/quit`, `/exit` | Leave the chat. The session keeps running. |
| `/help`, `/?` | The list of commands. |

`/switch` and `/new` need a terminal; elsewhere, use `resume` and `start`.

### Approvals in the chat

When the session asks you for something, the chat offers to answer it there:

* **An action**, such as a command that changes the agent: `Approve … now? [y/N]`. It runs with your rights. `/deny <id>` declines it.
* **A release card**: `Approve release brc_… now? [y/N]`. The card is in the Lua desktop app too. See [who can approve a release](#who-can-approve-a-release).
* **A secret**: you type the value with the input hidden. It goes to the agent's environment variables, never to the session; the session only learns that it is set.
* **Adding an agent** to a fleet session: confirm or decline it in the Lua desktop app.

Answer `n`, or anything that is not `y`, to leave it for later; a line that is not `y` or `n` is sent as a message. Whatever you don't answer stays in `lua build-session approvals` and in the Lua desktop app.

### Drop files on the terminal

Drag a file onto the terminal, or paste its path, and it goes with the message on the same line. A file dropped on its own waits for your next message. A path counts when it is absolute, starts with `~/` or is a `file://` URL, and the file exists; a word like `notes.txt` stays part of the message, and so does anything inside backticks. The chat asks before it attaches a file over 5 MB or outside your home folder.

Files Claude shares show up in the chat with their number, for example `/save 2 to download`. `chat --auto-save <dir>` saves each one as it arrives instead.

### File limits

| Limit | Value |
| - | - |
| File types | Images (`.png`, `.jpg`, `.jpeg`, `.gif`, `.webp`), `.pdf`, `.docx`, `.xlsx`, `.csv`, `.tsv`, `.json`, `.yaml`, `.yml`, `.md`, `.markdown`, `.txt` |
| One file | 25 MB |
| Files per message | 10 |
| One session | 500 MB in total |

The CLI checks the type and size before uploading. The platform checks the contents too and refuses a file whose contents do not match its type (`attachment_rejected`).

## Pick an organization and agent

`start`, `chat` and bare `lua build-session` without `--agent`, in a terminal, ask which agent to build:

1. **The organization.** This step is skipped when you belong to only one.
2. **The agent.** The agent in this project's `lua.skill.yaml` comes first, marked `[this project]`. Each agent shows your open or parked session, if it has one.
   * Picking an agent with your session offers to resume it or to start a session on another agent.
   * An agent another person is building is refused, because an agent has one session at a time. Pick another agent.
   * The last entry, **Fleet session: pick a supervisor…**, starts a fleet session on the supervisor agent you pick next, with its fleet members loaded too.

Bare `lua build-session` with an open current session first asks whether to continue it, pick another of your sessions, or start a new one.

Outside a terminal, with `--json`, with `--no-chat` or `--no-wait`, or under `--ci` or with `CI` set to `1` or `true`, nothing is asked. `start` then uses `--agent` or the agent in `lua.skill.yaml`, and bare `lua build-session` prints its help.

## Commands

### start

Opens a build session on the agent and waits until it is ready, then opens the chat in a terminal. Without `--agent`, a terminal gets the [picker](#pick-an-organization-and-agent); elsewhere the agent comes from `lua.skill.yaml`.

| Option | Description | Default |
| - | - | - |
| `--agent <agentId>` | The agent to build. | picker, or `lua.skill.yaml` |
| `--fleet` | A fleet session: the agent is the supervisor, and its fleet is loaded too. | off |
| `--resume` | Resume the agent's parked session instead of opening a new one. | off |
| `--base <base>` | Where to start when the live version and the latest saved source differ: `live` or `latest_saved`. | `live` |
| `--no-wait` | Return once the session is created, without waiting for it to be ready. | waits |
| `--timeout <seconds>` | How long to wait for the session to be ready. | `300` |
| `--no-chat` | Don't open the chat once the session is ready. | opens in a terminal |

### chat

Opens the [chat](#chat) on the current session, on `--session`, or on the agent's open or parked session. A parked session is resumed first. When the agent has no session, a terminal starts one. Without any of these, a terminal gets the picker.

| Option | Description | Default |
| - | - | - |
| `--agent <agentId>` | Chat on this agent's open or parked session. | current session |
| `--auto-save <dir>` | Save every file Claude shares into this folder as it arrives. | off |
| `--verbose` | Also print Claude's reasoning and tool output. | off |

`chat` is interactive and refuses `--json`; use `send` and `attach --json` in scripts.

### attach

Prints the session's activity as it happens: Claude's text, a line per tool step, file change, command, checkpoint, test and approval, and the credits spent. `Ctrl-C` stops following; the session keeps running.

| Option | Description | Default |
| - | - | - |
| `[sessionId]` | The session. | current session |
| `--after <n>` | Start after this event number. | from the start |
| `--until-idle` | Exit when the session is idle or parked again. | follow until `Ctrl-C` |
| `--timeout <seconds>` | Stop following after this long. Without `--until-idle` this is a bounded tail and exits `0`. | none |
| `--verbose` | Also print Claude's reasoning and tool output. | off |

### send

Sends a message and prints its turn until the session is idle again.

| Option | Description | Default |
| - | - | - |
| `--file <path>` | Attach a file. Repeat for more, up to 10. See [File limits](#file-limits). | none |
| `--interrupt` | Stop the running turn and run this message now. Without it, the message is queued behind the running turn. | queue |
| `--no-follow` | Return once the session has accepted the message. | follows |
| `--timeout <seconds>` | How long to follow the turn. | `1800` |
| `--verbose` | Also print Claude's reasoning and tool output. | off |

`Ctrl-C` stops following and exits `130`; the turn keeps running. Stop it with `lua build-session stop`.

### stop

Stops the running turn now. A queued message, if there is one, runs next.

### try

Sends a message to the session's version of the agent, the way an end user would, and prints the reply. Writes go to separate test data, and outbound calls are recorded instead of made.

| Option | Description | Default |
| - | - | - |
| `--live` | Make real outbound calls. Your organization must have consented to it. | off |
| `--agent <agentId>` | Fleet sessions: which agent to talk to. | the session's agent |
| `--thread <threadId>` | Continue an earlier try thread. | new thread |

### release

Builds the release candidate: what the session changes, its tests and its risk. The approval card opens in the Lua desktop app, and the command prints the candidate's state as it changes.

| Option | Description | Default |
| - | - | - |
| `--summary <text>` | What changes, in plain words. | written for you |
| `--approve` | Approve the candidate here once it is built. You need the right to promote the agent. | off |
| `--wait` | Wait until the release is live, or fails. | off |
| `--timeout <seconds>` | How long to wait. | `1800` |

With `--wait`, the command prints each agent's version change once the release is live, and exits `1` when the candidate is denied, fails, is rolled back or is superseded.

#### Who can approve a release

Approving a release from the CLI, with `release --approve`, `approve brc_…` or `y` in the chat, needs a person signed in with [`lua auth`](https://docs.heylua.ai/reference/cli/auth). An API key can approve only when the organization has turned on its `buildSessions.cliReleaseApprove` setting. Otherwise approve the card in the Lua desktop app.

### end, remove

Ends the session. Without an id, a terminal lets you pick one of your open sessions. `remove` (alias `rm`) does the same and says that ended sessions are removed automatically; there is no delete.

| Option | Description | Default |
| - | - | - |
| `[sessionId]` | The session. | current session, or a pick |
| `--save` | Save the session's work. | off |

### kill

Stops a session hard, without saving. Without an id, a terminal lets you pick one of your open sessions.

| Option | Description | Default |
| - | - | - |
| `[sessionId]` | The session. | current session, or a pick |
| `--reason <text>` | Why. Kept with the session. | none |

### list

Your build sessions across every organization and agent you can see, newest activity first. Each line shows the session id, its state, the organization and agent, `[fleet]` for a fleet session, when it was last active and the credits it spent today. `*` marks the current session.

| Option | Description | Default |
| - | - | - |
| `--all` | Include ended sessions. | open sessions only |

### use

Makes the session the current one. Nothing changes on the server.

### resume

Resumes a parked session, or re-attaches to an open one, and opens the chat. Without an id, a terminal lets you pick one of your sessions; elsewhere the command exits `2` and lists the sessions you can resume.

| Option | Description | Default |
| - | - | - |
| `[sessionId]` | The session. | a pick |
| `--no-chat` | Don't open the chat. | opens in a terminal |
| `--timeout <seconds>` | How long to wait for a parked session to come back. | `300` |
| `--verbose` | Also print Claude's reasoning and tool output. | off |

### approvals

Lists everything waiting on you across your open sessions: action requests (`bsa_…`), secret requests (`bss_…`) and release cards (`brc_…`). Each line shows the kind, the id, the session and agent, what it is, its risk, and how long ago it was asked.

| Option | Description | Default |
| - | - | - |
| `--session <sessionId>` | Only this session. | all your open sessions |
| `--all-sessions` | All your open sessions. | on unless `--session` is given |

Release cards are listed once the CLI on this computer has seen them, in `chat`, `attach`, `send` or `release`.

### approve, deny

`approve <id>` approves an action request (`bsa_…`), which then runs with your rights, or a release card (`brc_…`). `deny <id>` declines an action request or denies a release card; a denied release changes nothing, and the session keeps its work. The platform decides who may approve. `deny` takes `--reason <text>`, kept with a release decision.

Denying a release card needs a card the CLI on this computer has seen; otherwise deny it in the Lua desktop app, or open the chat on the session first.

### secret

Answers a secret request (`bss_…`). In a terminal you type the value with the input hidden; it is never a command-line argument. The value goes to the agent's environment variables, never to the session, and it is never printed.

| Option | Description |
| - | - |
| `--decline` | Decline the request. |
| `--from-stdin` | Read the value from piped input, for scripts. |

Outside a terminal, `secret` needs `--from-stdin` or `--decline`.

### files, download

`files` lists the session's files: the ones you sent and the ones Claude shared. `download` saves one by its id, or all of them with `--all`, into `./build-session-files/<sessionId>/`.

| Option | Description | Default |
| - | - | - |
| `[attachmentId]` | The file to save. Give this or `--all`. | none |
| `--all` | Every file of the session that can be downloaded. | off |
| `-o, --output <dir>` | Save into this folder. | `./build-session-files/<sessionId>/` |
| `-f, --force` | Overwrite a file that exists. | off |

### status

Shows the session: its state, the agent version and source it started from, the credits spent today and in total, the latest checkpoint and what is staged for testing. With `--agent <agentId>` and no session, it lists that agent's sessions instead.

## Output

`--json` prints one JSON object per line, each with a `kind`. The stream of a session arrives as `{"kind":"event", …}`, `{"kind":"state", …}`, `{"kind":"ack", …}` and `{"kind":"error", …}` lines; a command that follows the stream ends with a `{"kind":"result", "verb", "outcome", …}` line. One-shot commands print a single line of their own kind, such as `session`, `started`, `session-list`, `approvals`, `files`, `downloaded`, `release`, `try`, `ended` or `killed`.

```bash theme={null}
lua build-session attach --json | jq 'select(.kind=="event")'
```

## Out of credits

When your organization runs out of credits, the session stops with `credits_exhausted`, the message `Your organization is out of credits. Top up to keep building.` and a link to top up your balance. The command exits `13`. A daily credit cap on the session is a different refusal, `budget_exhausted`; it resets at midnight UTC.

## Examples

Chat with the current session, or pick an agent:

```bash theme={null}
lua build-session
```

Start a session on an agent without the picker:

```bash theme={null}
lua build-session start --agent <agentId>
```

Send a message with a file, then change course mid-turn:

```bash theme={null}
lua build-session send "Add a tool that looks up an order by id" --file spec.pdf
lua build-session send "Actually, call it find_order" --interrupt
```

Try the session's version of the agent:

```bash theme={null}
lua build-session try "Where is order 1234?"
```

Release and wait until it is live:

```bash theme={null}
lua build-session release --wait
```

See everything waiting on you, then answer it:

```bash theme={null}
lua build-session approvals
lua build-session approve bsa_…
lua build-session secret bss_…
```

Set a requested secret from a script:

```bash theme={null}
printf '%s' "$STRIPE_KEY" | lua build-session secret bss_… --from-stdin
```

Save every file of the session:

```bash theme={null}
lua build-session download --all -o ./from-claude
```

End the session and keep the work:

```bash theme={null}
lua build-session end --save
```

## Common refusals

| Code | Meaning |
| - | - |
| `build_sessions_disabled` | Build sessions are off for this organization. |
| `session_locked` | Another person's session holds this agent. Ask them to end it, or take it over in the Lua desktop app. |
| `base_moved` | The agent changed since the session started. A release merges the changes; check `/diff` first. |
| `credits_exhausted` | The organization is out of credits. Exit code `13`. |
| `budget_exhausted` | A daily credit cap is reached. It resets at midnight UTC; an admin can raise or remove it. |
| `quota_full` | All build sessions for your organization are busy. Try again in a few minutes. |
| `session_not_found` | No such session. List them with `lua build-session list`. |
| `session_ended` | The session has ended. Start a new one. |
| `killed` | The session was stopped by an administrator. |
| `attachment_rejected` | The file was refused for its type, size or contents. |
| `rate_limited` | Too many requests. Wait a minute and try again. |

## Exit codes

| Code | Meaning | When |
| - | - | - |
| `0` | OK | The command finished, you left the chat, or an `attach --timeout` without `--until-idle` ran out. |
| `1` | Error | The session failed or was killed, a release did not go live, a wait timed out (the session keeps going), or a file was not saved. |
| `2` | Usage | A bad option or id, no current session, nothing to send, or a command that needs a terminal run outside one. |
| `3` | Not found | The session does not exist, or build sessions are off for the organization (`build_sessions_disabled`). |
| `9` | Auth | No valid credential, or it expired. Sign in again with `lua auth configure`. |
| `10` | Refused | You may not do this, the platform refused the request (for example `session_locked`, `budget_exhausted` or `rate_limited`), or `deny` names a release card the CLI on this computer has not seen. |
| `11` | Unavailable | The platform or the network is not reachable, all build sessions for the organization are busy (`quota_full`), or build sessions are not available in this environment. |
| `13` | Out of credits | The organization is out of credits (`credits_exhausted`). Top up, then try again. |
| `130` | Stopped following | You pressed `Ctrl-C` during `send`. The turn keeps running. |

The full table is in [Errors and exit codes](https://docs.heylua.ai/reference/cli/errors-and-exit-codes.md).

## Environment variables

| Variable | Description |
| - | - |
| `LUA_BUILD_SESSIONS_ENABLED` | `true` lists `build-session` in `lua --help`. The commands work without it. |
| `LUA_BUILD_SESSION_ID` | The session to use when no id or `--session` is given. Wins over the remembered current session. |

## See also

* [`lua chat`](https://docs.heylua.ai/reference/cli/chat) — talk to the agent in sandbox or production
* [`lua auth`](https://docs.heylua.ai/reference/cli/auth) — sign in, which a release approval from the CLI needs
* [`lua version`](https://docs.heylua.ai/reference/cli/version) — the agent versions a release promotes
* [Errors and exit codes](https://docs.heylua.ai/reference/cli/errors-and-exit-codes.md) — every exit code, including `13`


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