---
title: "hoplite ask"
description: "Run one Hoplite request from a script or another tool, with plain text or JSON output."
canonical_url: "https://hoplite.sh/docs/cli/ask"
markdown_url: "https://hoplite.sh/docs/cli/ask.md"
---

# hoplite ask
URL: /docs/cli/ask
LLM index: /llms.txt
Description: Run one Hoplite request from a script or another tool, with plain text or JSON output.
Related: /docs/cli, /docs/cli/interactive, /docs/automations

# hoplite ask

`hoplite ask` runs one request on a Hoplite thread and exits when the run ends. Use it in scripts, git hooks, or other tools where the [interactive session](/docs/cli/interactive) doesn't fit.

```bash title="terminal"
hoplite ask "Explain the changes in this repository"
```

Each request starts a new thread unless you pass `--resume`. The thread is saved in Hoplite like any other, so you can open it in the app or `hoplite --resume ID` later.

## Usage

```text
hoplite ask [--resume[=<id>]] [--attach <path>]... [--model <id>] [--reasoning <level>] [--json[=stream]] [--quiet] [--no-color] [--] <prompt>
```

| Option | What it does |
| --- | --- |
| `--resume` | Continue the latest thread in this repository |
| `--resume=ID` | Continue the thread with this ID |
| `--attach PATH` | Send a local file with the prompt. Repeat it for more files. `--attach -` sends standard input as a file |
| `--allow-credentials` | Allow `--attach` to send files that look like credentials, such as `.env` files and private keys |
| `--model ID` | Select a model before sending the prompt, including when resuming a thread |
| `--reasoning LEVEL` | Select a reasoning level supported by the chosen model |
| `--json` | Print one JSON result object instead of text |
| `--json=stream` | Print newline-delimited JSON events as they arrive, followed by the final result object |
| `--quiet` | Print no assistant output; use the exit status |
| `--no-color` | Render terminal output without colors or hyperlinks |
| `--` | Treat every following argument as prompt text |

Pass the prompt as arguments, or pipe it on stdin when there are no prompt arguments:

```bash title="terminal"
git diff main | hoplite ask
```

## Attach files

The agent works in a cloud sandbox and can't see your files, so send the ones it needs with the prompt:

```bash title="terminal"
hoplite ask --attach screenshot.png "Why does the header overlap the menu?"
hoplite ask --attach build.log --attach package.json "Why does the build fail?"
```

When you pass the prompt as arguments, anything piped on stdin goes with it as a file named `stdin.txt` (or `stdin.png`, `stdin.pdf`, and so on for images and PDFs):

```bash title="terminal"
npm test 2>&1 | hoplite ask "Why do these tests fail?"
```

To send no stdin, for example when `hoplite ask` runs in a `while read` loop, redirect it: `hoplite ask "..." </dev/null`.

Small text files go with the prompt as text. Other files, including images, are uploaded to Hoplite first, and the thread keeps them as attachments, as in the web app. The agent finds them in its workspace under `.hoplite/attachments/`. Each file can be up to 50 MB, and a prompt can carry up to 10 files. A file that doesn't exist, is too large, or looks like credentials (without `--allow-credentials`) stops the request before anything is sent, with exit status `1` and, with `--json`, the error `AttachmentRejected`.

## Output

What `hoplite ask` prints depends on where stdout goes:

| stdout | Output |
| --- | --- |
| A terminal | The rendered transcript, with tool calls and formatting |
| A pipe or file | The assistant's raw text |
| `--json` | One JSON object |
| `--json=stream` | Newline-delimited events followed by one result object |
| `--quiet` | Nothing |

| Exit status | Meaning |
| --- | --- |
| `0` | The run succeeded |
| `1` | The run failed, or it couldn't start (for example, not signed in; with `--json` its `error` is `NotSignedIn`) |
| `130` | Interrupted with **Ctrl+C** (`SIGINT`) |
| `143` | Stopped with `SIGTERM` |

On `SIGINT` or `SIGTERM`, `hoplite ask` stops the run in Hoplite, waits for the stop to settle, then exits without printing a result (not even with `--json`).

### JSON

`--json` prints a single object on stdout:

```json title="output"
{
  "output": "The change adds retry logic to the uploader…",
  "final_output": "The change adds retry logic to the uploader…",
  "threadId": "<thread-id>",
  "exit_code": 0,
  "steps": 3,
  "tool_calls": [
    { "name": "Run tests", "status": "completed" }
  ]
}
```

`threadId` is the Hoplite thread the request ran on. Pass it to `hoplite ask --resume=ID` or `hoplite --resume ID` to continue it. It is missing when no thread was created, for example when Hoplite couldn't be reached.

With `--json=stream`, each event has a `type`: `thread`, `assistant_text`, `tool_call_started`, `tool_call_completed`, or `usage`. Concatenate `assistant_text` chunks to reconstruct `output`. The final line is the same result object as `--json`, without a `type` field. Diagnostics stay on stderr; interruption can end the stream before the final result. Invalid model or reasoning selections fail without sending the prompt, and `/retry` cannot take either selection because it uses the previous run's settings.

When the request fails, the object also has an `error` code, such as `HopliteTurnFailed`, `NoThreadToResume`, or `ThreadResumeFailed`. When the run itself failed, `failure` carries Hoplite's failure details: its code, message, when a usage limit resets, and the available actions.

## Failed runs

Without `--json`, a failed run prints a plain-text summary of Hoplite's failure card on stderr: what failed, when a usage limit resets, and the command or page for each action. To retry the thread's last run, resume it with `/retry` as the prompt:

```bash title="terminal"
hoplite ask --resume /retry
hoplite ask --resume=<thread-id> /retry
```

`/retry` needs `--resume`, because a new thread has no run to retry.

## Approvals and questions

`hoplite ask` can't prompt you. When a tool needs approval or the agent asks a question, the CLI says so on stderr and the approval or question stays pending on the thread. Answer it in the Hoplite app, or `hoplite --resume ID` to answer it in the terminal.

## Sign-in and connection

When no CLI key is stored, or Hoplite no longer accepts the stored one (such as a key stored by CLI 2.x), `hoplite ask` opens the browser [sign-in](/docs/cli#sign-in) once before it runs. Without a terminal to sign in from (standard input or standard error isn't a terminal, as in CI), it fails at once with exit status `1` and asks you to run `hoplite login` in a terminal first. When Hoplite can't be reached, it fails straight away with the reason and exit status `1`; unlike the interactive session, it doesn't retry in the background.

## Sitemap

Sitemap discovery is not enabled for this deployment.
