---
title: "Interactive sessions"
description: "Prompt, queue, steer, and resume Hoplite threads from the terminal."
canonical_url: "https://hoplite.sh/docs/cli/interactive"
markdown_url: "https://hoplite.sh/docs/cli/interactive.md"
---

# Interactive sessions
URL: /docs/cli/interactive
LLM index: /llms.txt
Description: Prompt, queue, steer, and resume Hoplite threads from the terminal.
Related: /docs/cli, /docs/cli/commands, /docs/threads/run, /docs/agent/models

# Interactive sessions

`hoplite` opens an interactive session in your terminal. The session is a Hoplite [thread](/docs/threads): the agent works in the project's cloud sandbox, and the conversation is saved in Hoplite, not on your machine.

The CLI connects while it starts. Before your first prompt, the footer shows the thread's model settings and a header above the composer names the project, repository, local branch, and workspace. A new session doesn't create a thread until you send a prompt, so nothing is recorded until then. Once the thread exists, the header adds an **Open in Hoplite ↗** link to it.

## The composer

Type a prompt and press **Enter**. The answer, tool calls, and file edits stream into the transcript. Edits show as red and green diffs under their tool row. While the sandbox starts, the footer shows the setup phase, such as **Starting sandbox**.

Tool activity remains in the transcript when you reconnect to a thread, including its outcomes and expandable details. Command results show a short inline output preview; open the tool row for the full result rather than treating the preview as the complete log.

The model's reasoning is kept apart from its answer. While the model thinks, the footer shows **Thinking**, and each thought then shows as one `∴` row in the run's activity group, which counts thoughts next to its tool calls, such as **● 1 thought · 1 tool call**.

Type `/` to open the slash-command menu. It lists the built-in [slash commands](/docs/cli/commands) and the thread's [skills](/docs/cli/commands#skills). **Up** and **Down** recall your earlier prompts.

### Long pastes and attachments

A paste of more than 3,500 characters shows in the composer as a chip, such as **[Pasted text · 4,212 chars]**, and is sent as an attachment named `pasted-text.txt`, as in the web app. One **Backspace** removes the chip. A message can carry about 900 KB in total. A paste that would make it larger isn't added, and a notice gives its size.

Attachments show in the transcript as chips with their names, such as **[pasted-text.txt]**, for your messages and your teammates', when you resume a thread and in the queue. In terminals that support links, clicking a chip in the transcript opens the attachment. Opening it needs you to be signed in to Hoplite in your browser. **Ctrl+O** shows each attachment's name and link, since the thread doesn't store its text in the message.

### Attach files and images

The agent works in a cloud sandbox, so it can't see files on your computer. To give it one, attach it to your message. Each file shows in the composer as a chip with its name and size, such as **[screenshot.png · 1.2 MB]**, so you can check it before you send. One **Backspace** removes a chip.

| How | What happens |
| --- | --- |
| Type `@` and a path, such as `@logs/build.log` | **Tab** completes the path from the current directory, like a shell. When it completes to a file, the file becomes a chip. When you press **Enter**, each `@path` that names a file becomes a chip and the message waits, so press **Enter** again to send it. An `@word` that doesn't name a file stays text |
| `/attach PATH` | Attaches the file. Paths can be absolute, relative to the current directory, or start with `~/`, and can contain spaces |
| Drag a file into the terminal | The terminal types the file's path, and the CLI attaches it. Dropping several files attaches each one |
| **Ctrl+V** or `/paste` | Pastes the clipboard's text. When the clipboard holds an image instead, such as a screenshot, it's attached as `pasted-image.png` |

Pasting an image needs `osascript` on macOS (built in), and `wl-paste` (Wayland) or `xclip` (X11) on Linux. Without them, the CLI says so and nothing is attached.

When you send the message, small text files go with it as text, like a long paste. Other files, including images and PDFs, are uploaded to Hoplite first. The footer shows **Uploading NAME** while they upload, and **Esc** twice stops the upload without sending. Uploads go to the Hoplite API, as the rest of the CLI's traffic does. The thread keeps each file as an attachment, as the web app does, and the agent finds it in its workspace under `.hoplite/attachments/`.

A few limits and safeguards apply:

- Each file can be up to 50 MB, and a message can carry up to 10 attachments, pasted text included. Folders can't be attached; attach the files in them.
- The CLI reads a file only when you send the message, and only the files you named. If a file changed since you attached it, the message carries its current contents. If it's gone, the message isn't sent and a notice says why; press **Up** to get the message back.
- Files that look like credentials, such as `.env` files, private keys (`id_rsa`, `*.pem`), and cloud credentials, ask for confirmation first, because the agent and your teammates on the thread can read attachments. Choose **Attach anyway** to attach one.
- Prompt history keeps attached files as their `@path`, so **Up** and **Enter** attach them again. Pasted images are kept in `~/.hoplite/attachments/` for a week.

### Queue or steer while the agent works

You can keep typing while a run is working:

In the limited guidance rollout, **Enter** guides the active run without stopping it, while **⌘↵** (or **⌃↵** elsewhere) queues a message for a later run. Outside the rollout, the shortcuts have the opposite delivery behavior:

| Key | What it does |
| --- | --- |
| **Enter** | Outside the guidance rollout, queue the message for the running run's next step; with guidance enabled, guide the active run |
| **⌘↵** (Cmd+Enter) on macOS, **⌃↵** (Ctrl+Enter) elsewhere, or **⌥↵** (Alt+Enter) | Outside the rollout, interrupt the run and send the message now; with guidance enabled, queue it for later |

A queued message shows above the composer until the agent picks it up, then moves into the transcript where it joined. A run that can't take a message mid-run, such as a compaction, runs it after it ends instead. Messages your teammates queued on the same thread show above the composer too. Press **Up** to edit your newest message that is still waiting for the run to end. While you edit it, **Enter** saves the edit and **Enter** on an empty composer deletes it. Outside the guidance rollout, **⌘↵** (**⌃↵** off macOS) sends that edit now; with guidance enabled, it saves the edit without stopping the run. If the message starts running before you save the edit, your text stays in the composer.

**⌘↵** reaches the CLI only in terminals that report the Cmd key, such as kitty, Ghostty and WezTerm. In others, such as Terminal.app and inside tmux, use **⌥↵** or **⌃↵**.

When no run is active, **Enter** and **⌘↵** / **⌃↵** both send the message, and **⌥↵** inserts a new line. The web app's version of these controls is described in [Run a thread](/docs/threads/run#send-messages-while-the-agent-works).

### Run a command in the sandbox

Start a line with `!` to run it as a shell command in the thread's sandbox, such as `!git status` or `!npm test 2>&1 | tail -20`. The composer shows a pink `$` marker and **! runs in the sandbox** while the line starts with `!`.

The command runs right away, even while the agent works; it isn't queued behind the run. It isn't sent to the agent or saved in the thread: only your terminal shows it. Its output shows in the transcript with standard error in its own color, then ✓ or ✗ with the exit code, and how long it took. Long output shows its first 20 lines; **Ctrl+O** shows the rest. Press **Esc** twice to cancel a command that is still running, which stops it in the sandbox too. **Up** recalls `!` lines like your prompts, and they are saved in your prompt history (`~/.hoplite/history.jsonl`). To keep a command out of history, for example one with a token in it, put a space after the `!` (`! export TOKEN=...`), as with bash's `HISTCONTROL=ignorespace`.

The sandbox starts with the thread's first prompt, so in a new session, send a prompt first. Commands run in a login `bash` at the repository root with the sandbox's base environment, not the project's secrets, and stop after 120 seconds. Avoid changing files the agent is working on. From outside a session, [`hoplite exec`](/docs/cli/commands#run-commands-in-the-sandbox) runs a command the same way.

### Send local changes to the sandbox

`/sync` sends your uncommitted local changes, including untracked files, to the thread's sandbox, where they apply on the same commit, merging with any changes the sandbox made. The transcript lists the files it sent and what happened, including conflicts; nothing is added to the thread. Press **Esc** twice to cancel it. Credential files such as `.env` are never sent. See [Send local changes to the sandbox](/docs/cli/commands#send-local-changes-to-the-sandbox) for the details and `hoplite push`.

### Open a shell in the sandbox

`/shell` hands your terminal to an interactive shell in the thread's sandbox, like `ssh`. Every key goes to the sandbox, including **Ctrl+C**. Type `~.` at the start of a line to come back to the session; replies and updates that arrived meanwhile show then. See [Open a shell in the sandbox](/docs/cli/commands#open-a-shell-in-the-sandbox) for the escapes and `hoplite shell`.

### Stop a run

Press **Esc** twice to stop the run you started. Queued messages still run afterwards. While a `!` command runs, **Esc** twice cancels that command first. `/stop` stops whatever is running on the thread, including a teammate's run.

### Approvals and questions

When a tool needs approval, an **Approval needed** card shows what the agent wants to do. For a file edit, the card includes the diff. Choose **Allow** or **Reject**. See [Approvals](/docs/threads/review#approvals) for how approval policies work.

When the agent asks a question, it shows as a question card. Answer it in the card, or press **Esc** to decline.

### Full transcript

The inline transcript keeps tool output short. Press **Ctrl+O** to open the full transcript, with complete diffs, long task lists, and every tool's output. Use **PgUp** and **PgDn** to scroll, and **Ctrl+O** or **Esc** to close it.

## MCP servers on your machine

The agent runs in the cloud, so it can't reach MCP servers that only run on your computer, such as a design tool's desktop MCP server. `--mcp` lets it use them through your CLI session:

```bash
hoplite --mcp paper=http://127.0.0.1:29979/mcp
```

The CLI lists the server's tools and offers them to the agent in this session. When the agent calls one, the request comes back down your CLI's connection to Hoplite. The CLI then calls the server on your machine and sends the result back. Each server appears to the agent as one more MCP server, such as `mcp_server_901`, and keeps that name for the thread.

Pass `--mcp` once for each server, up to 8. The name is lowercase letters, digits, and underscores. The URL must be a [Streamable HTTP](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports#streamable-http) endpoint on `localhost`, `127.0.0.1`, or `[::1]`. stdio servers aren't supported yet. To configure servers once instead of on every launch, add them to [`settings.json`](/docs/cli/configuration#mcp-servers-on-your-machine) or set `HOPLITE_LOCAL_MCP`.

### Read-only unless you allow writes

By default the agent sees only the tools the server marks read-only (`readOnlyHint: true`). Tools that change things are left out, and the agent is told how many were. To offer them too, add `write`:

```bash
hoplite --mcp paper=http://127.0.0.1:29979/mcp,write
```

The CLI enforces this itself. It refuses a call to a tool it didn't offer, whatever Hoplite asks for.

### Approving calls

Each call waits for your approval in this CLI. The **Approval needed** card names the server and tool, says whether the tool only reads or can change things, and shows the arguments. Choose **Allow once**, **Allow paper for this session**, or **Reject**. The run waits until you answer. If this CLI exits first, the run keeps waiting in Hoplite: stop it with `/stop`, or resume the thread with the same `--mcp` server to be asked again.

Only the CLI that offered the server can answer. The web app and your other sessions can't approve these calls, even your own.

`hoplite ask` can't show a card. To use a server there, add `trust`, which runs its calls without asking:

```bash
hoplite ask --mcp paper=http://127.0.0.1:29979/mcp,trust "Summarize the open Paper file"
```

Use `trust` only for servers you'd let the agent use unsupervised.

### How your machine is protected

- **Only your runs.** Only runs started by your own messages see your servers. A teammate's message on the same thread doesn't, and your servers never reach their machines.
- **Only while you're connected.** The tools exist while this CLI session is open. Within a few seconds of it exiting, crashing, or losing its connection, they are gone: calls fail and the agent is told the server is unavailable.
- **Only the servers you name.** Once a server is configured, the CLI connects to no other port on your machine. Hoplite's own traffic isn't affected.
- **Untrusted data.** Hoplite shortens each tool's description and input schema and strips markup from them before the agent sees them. The agent is told that descriptions and results from your machine are data, not instructions.
- **Bounded calls.** Each call must finish within 55 seconds. A result can be at most 512 KB, and a larger one fails with an error telling the agent to ask for less. At most 16 calls run at once.

A call's arguments and result are saved in the thread like any other tool call's. Hoplite's service logs never include them.

## Commands on your machine

Some work needs your computer, not the sandbox. For example, the agent edits an iOS app in the sandbox, then builds it with `xcodebuild` and installs it on your phone with `xcrun devicectl`. With `--local-exec`, the agent can ask to run shell commands on your computer through your CLI session:

```bash
hoplite --local-exec
```

This is off unless your workspace has local commands enabled. Hoplite staff turn it on per workspace; ask support. When it's off, the CLI says so after it connects and the agent never sees the tool. To opt in on every launch instead, set `"localExec": {"enabled": true}` in [`settings.json`](/docs/cli/configuration#commands-on-your-machine). A repository's `.hoplite.json` can't opt your machine in.

### Approving commands

Each command waits for your approval in this CLI. The CLI prints the whole command and the directory it will run in, then shows a **Run on your computer** card with the command, the directory, and the timeout. Choose **Allow once**, **Allow `xcodebuild` in ~/code/app for this session**, or **Reject**. The session option appears only for simple commands (no pipes, `;`, `&&`, redirections, or `$(...)`), and never for shells, interpreters, or tools such as `sudo`, `curl`, or `rm`. The run waits until you answer. If this CLI exits first, the run keeps waiting in Hoplite; resume the thread with `--local-exec` to be asked again.

Only this CLI can answer. The web app and your other sessions can't approve these commands, even your own. `hoplite ask` can't show a card, so there a command runs only if one of your rules allows it.

The CLI checks for itself too. It runs a command only if you approved exactly that command in exactly that directory here, once, or one of your rules allows it, whatever Hoplite sends.

### Rules

Rules in `settings.json` let simple commands run without a card. A rule is the words a command starts with, and optionally the directory it may run in (the repository root and anything under it by default):

```json
{
  "localExec": {
    "enabled": true,
    "allow": [
      "xcodebuild",
      { "command": "xcrun devicectl", "dir": "/Users/me/code/app" }
    ]
  }
}
```

A rule never matches a command with pipes, lists, redirections, substitutions, or globs, so `xcodebuild && curl ... | sh` still asks.

### How commands run

- **Where.** In the repository you started `hoplite` in, or a directory the agent names. The card marks a directory outside the repository.
- **How.** With `/bin/sh -c`, in its own process group, with input from `/dev/null`. The command inherits your environment except `HOPLITE_API_KEY` and `HOPLITE_ACP_API_KEY`.
- **How long.** Up to its timeout: 2 minutes unless the agent asks for longer, at most 30 minutes. Then, or when the run is stopped, the command and everything it started get `SIGTERM`, then `SIGKILL` 2 seconds later. At most 4 commands run at once.
- **What comes back.** The exit code (or signal), and stdout and stderr: the first 16 KB and last 48 KB of each, with how much was left out. The agent is told the output is data, not instructions.
- **Only yours, only while connected.** Hoplite offers local commands only on threads you started, only to runs started by your own messages, and only while this CLI is connected. Teammates' runs never reach your computer.

A command and its output are saved in the thread like any other tool call. Hoplite's service logs record only that a command ran, how long it took, and its exit code, never the command or its output.

## Keyboard shortcuts

| Key | Action |
| --- | --- |
| **Enter** | Send, or guide an active run when the rollout is enabled; otherwise queue for its next step |
| **⌘↵** (macOS), **⌃↵**, **⌥↵** | Queue for later with guidance enabled; otherwise interrupt the run and send now |
| **Shift+Enter**, **⌥↵** when idle, **Ctrl+J** | Insert a new line |
| **Up**, **Down** | Prompt history; **Up** edits your newest queued message while a run works |
| **Esc Esc** | Cancel a running `!` command, else stop your run; with neither, clear the draft |
| **!** at the start of a line | Run the line in the thread's sandbox |
| **Ctrl+O** | Open or close the full transcript |
| **Tab** | Complete an `@path`; switch between **Mine** and **Team** in the `/resume` picker |
| **Ctrl+V** | Paste the clipboard's text, or attach the image on it |
| **Ctrl+A**, **Ctrl+E** | Move to the start or end of the line |
| **Ctrl+U**, **Ctrl+K**, **Ctrl+W** | Delete to line start, to line end, or the previous word |
| **Ctrl+Y** | Paste the last deleted text |
| **Ctrl+L** | Redraw the screen |
| **Ctrl+C** twice | Exit (`/quit` works too) |

## Resume a thread

Hoplite keeps the conversation, so you can continue any thread later. Resuming replays the thread's messages into the transcript.

| Command | Opens |
| --- | --- |
| `hoplite -c` or `hoplite --resume` | The latest thread you used in this repository |
| `hoplite -r` | A picker of your recent threads in this repository |
| `hoplite --resume ID` | The thread with this ID |
| `/resume` | A picker inside the session |

The `/resume` picker lists the project's threads from Hoplite. It opens on **Mine**; press **Tab** for **Team** to see your teammates' threads, and type to search. If Hoplite opens a teammate's thread only for its followers, the CLI tells you so; select it in `/resume` again to follow and open it.

### Switch projects

The CLI starts in the project linked to the repository's Git remote. `/project` (or `/org`) lists every project you can reach, grouped by organization; type to filter it. Pick one and the CLI connects to it and shows its threads, with **New thread** first, so you can continue one or start fresh. The choice is saved for this checkout in `~/.hoplite/projects.json` (never in the repository), and the next `hoplite`, `hoplite ask`, `exec`, `shell`, or `push` here starts in it. **Use the repository's linked project** at the top of the list forgets it. `HOPLITE_PROJECT_ID` still takes precedence over a saved choice. This also works in a directory that isn't linked to any project.

`/new` and `/clear` start a new thread. `/rename TITLE` renames the current thread. Before the thread exists, the title is used for the thread that your first prompt creates.

`/pin` lists the current thread first in the `/resume` picker, and `/note TEXT` adds a note that the picker shows next to it. Like the web app's pins and notes, they stay on this device. `/follow` adds a teammate's thread to **Mine**, and `/unfollow` removes one you followed. `/unarchive` restores an archived thread, and `/delete` deletes the thread for everyone after you confirm. See [Pins, notes, and following](/docs/cli/commands#pins-notes-and-following).

The `/resume` picker opens on the rows it last received for this repository and account while the fresh list loads, and the CLI reads your **Mine** list in the background at launch so the picker opens quickly. These rows are kept in `~/.hoplite/thread-list-cache.json`.

The CLI stores no transcripts. It keeps a list of the threads you used in `~/.hoplite/threads.json` (ID, repository, title, last used, and any pin or note), which `-c`, `-r`, and the offline picker use.

## Work with teammates

Threads are shared with your workspace. When a teammate opens the thread in Hoplite or in their own terminal:

- The footer shows who else has the thread open, in Hoplite or in a terminal, for example **Ada viewing** or **Ada, Bo viewing**. It says **Ada composing** while Ada is typing a message. Teammates see you the same way, as composing while your composer holds text.
- Their messages show with their name above the prompt card.
- Their messages and runs appear in your transcript live, between your own turns. The footer shows who is running, for example **Ada is running**.
- Their queued messages show above the composer next to yours.
- If their run fails, the failure card says it was a teammate's run.

`/stop` stops a teammate's run as well as yours; **Esc Esc** only stops your own.

## Model, reasoning, and speed

The footer shows the thread's model, reasoning level, and speed.

| Command | What it does |
| --- | --- |
| `/model` | Pick the thread's [model](/docs/agent/models). `/model MODEL` switches directly |
| `/reasoning` (or `/effort`) | Pick the model's reasoning level. `/reasoning LEVEL` sets it directly |
| `/fast` | Turn the fast (priority) speed on or off, for models that support it. Its row in the command menu and `/help` says in green or red whether the current model has fast mode, and the `/model` picker marks models that do with ⚡︎ |

On a thread that already has messages, changing the model compacts the thread's context before the next prompt, as it does in the web app. The `/model` picker asks first, so you can switch and compact or keep the current model. `/model MODEL` switches at once and tells you afterwards.

## When a run fails

A failed run shows Hoplite's failure card: what went wrong, when a usage limit resets, and the actions available. Each action shows the command that takes it.

When your own run fails and the composer is empty, the actions also open as a list above the composer. Press **Up** and **Down** to move through them and **Enter** to take one: a command runs, and a page such as **Add credits** opens in your browser. Press **Esc** to dismiss the list. Any other key closes it and does what it normally does: text, digits included, goes to the composer, and **Ctrl+C**, **Ctrl+D**, **Ctrl+O** and **Tab** work as usual.

| Command | What it does |
| --- | --- |
| `/retry` | Retry the last failed run |
| `/retry hoplite` | Retry on Hoplite credits, when a linked subscription's usage limit was reached |
| `/continue` | Continue in a new thread |
| `/model`, `/reasoning` | Switch settings when the card suggests it |

Actions that lead to a page, such as **Add credits**, are links you can open in your browser. See [Retry a run](/docs/threads/run#retry-a-run) for what a retry does on the server.

## Offline and reconnecting

- **Hoplite can't be reached at startup** (connection refused, DNS, TLS, or a server error): one notice says so, and the CLI keeps retrying in the background. It tells you when the connection is back.
- **You send a prompt while offline**: the prompt is not queued. It fails at once and says it was not sent. Press **Up** to get it back.
- **The connection drops during a run**: the CLI reconnects, reopens the thread, and follows the run to its end. Press **Esc Esc** to stop waiting.
- **`/resume` while offline**: the picker falls back to the local thread list.

The work itself runs in Hoplite, so losing your connection or closing the terminal doesn't stop a run.

## Sitemap

Sitemap discovery is not enabled for this deployment.
