# Headless mode

Available on: Antigravity CLI

Run Antigravity CLI non-interactively to script agent tasks, integrate with CI pipelines, and capture machine-readable output.

Headless mode (also called print mode) sends a single prompt to the agent, streams or returns the response, and exits. Use it whenever you need the agent’s output in a program instead of a terminal UI.

## Run a single prompt

Pass a prompt with `-p` (or its aliases `--print` and `--prompt`) to run once and exit:

```bash
agy -p "In one sentence, what is a git rebase?"
```

```text
A git rebase rewrites the commit history by transplanting a sequence of commits onto a new base commit, imposing a strictly linear progression of changes that eliminates arbitrary merge artifacts.
```

The response goes to `stdout`. Diagnostics—errors, authentication prompts, progress, and permission notices—go to `stderr`. This split keeps the captured response clean:

```bash
# Capture only the model response; diagnostics still print to the terminal.
answer=$(agy -p "Name three popular version control systems, comma-separated.")
```

> **Note:** Headless mode uses your cached credentials. Authenticate once with an interactive `agy` session first. In a non-interactive environment with no terminal (for example, CI), a run that isn’t already authenticated exits with an `authentication required` error instead of hanging.

## Output formats

The `--output-format` flag controls the shape of `stdout`. It accepts three values:

| Format | `stdout` shape | Use it for |
| --- | --- | --- |
| `text` | The response text (default) | Human-readable output, quick scripts |
| `json` | One JSON object printed on completion | Capturing a result plus metadata |
| `stream-json` | Newline-delimited JSON (NDJSON) events | Monitoring progress, tools, and token usage |

### Text

This is the default format. The response text goes straight to `stdout` with no wrapping:

```bash
agy -p "In one sentence, what does the command git bisect do?"
```

```text
Git bisect executes a binary search algorithm across a project's commit history to rapidly isolate the precise commit responsible for introducing a defect.
```

### JSON

Set `--output-format json` to get a single JSON envelope after the run completes. The CLI emits it on one line; pipe through `jq` to pretty-print:

```bash
agy -p "In one sentence, what is a git rebase?" --output-format json | jq
```

```json
{
  "conversation_id": "055a398f-db14-4c5f-abbb-1bf03f8120a7",
  "status": "SUCCESS",
  "response": "A git rebase rewrites the commit history by transplanting a sequence of commits onto a new base commit, imposing a strictly linear progression of changes that eliminates arbitrary merge artifacts.\n",
  "duration_seconds": 7.16,
  "num_turns": 1,
  "usage": {
    "input_tokens": 10415,
    "output_tokens": 657,
    "thinking_tokens": 616,
    "cache_read_tokens": 8113,
    "total_tokens": 11072
  }
}
```

The envelope contains these fields:

| Field | Type | Description |
| --- | --- | --- |
| `conversation_id` | string | ID of the conversation, for resuming later |
| `status` | string | Terminal status (refer to [Status values](#status-values)) |
| `response` | string | The agent’s free-text response |
| `error` | string | Error message; present only on failure |
| `duration_seconds` | number | Wall-clock duration of the run |
| `num_turns` | number | Number of user turns in the conversation |
| `structured_output` | object | Parsed schema output; present only with `--json-schema` |
| `json_schema` | object | The schema that was enforced; present only with `--json-schema` |
| `usage` | object | Token counts: `input_tokens`, `output_tokens`, `thinking_tokens`, `cache_read_tokens`, `total_tokens` |

#### Structured output with a schema

Pass `--json-schema` to constrain the answer to a schema. The parsed object appears in `structured_output`, and `response` holds the same payload serialized as a string:

```bash
agy -p "Parse the semantic version string v2.14.3 into an object with integer fields major, minor, and patch." \
  --output-format json \
  --json-schema '{"type":"object","properties":{"major":{"type":"integer"},"minor":{"type":"integer"},"patch":{"type":"integer"}},"required":["major","minor","patch"]}' | jq
```

```json
{
  "conversation_id": "4e502687-290c-4030-b908-5ed6c68fa5dc",
  "status": "SUCCESS",
  "response": "{\"major\":2,\"minor\":14,\"patch\":3}\n",
  "duration_seconds": 4.45,
  "num_turns": 1,
  "structured_output": { "major": 2, "minor": 14, "patch": 3 },
  "json_schema": {
    "type": "object",
    "properties": {
      "major": { "type": "integer" },
      "minor": { "type": "integer" },
      "patch": { "type": "integer" }
    },
    "required": ["major", "minor", "patch"]
  },
  "usage": { "input_tokens": 10522, "output_tokens": 354, "thinking_tokens": 329, "cache_read_tokens": 8112, "total_tokens": 10876 }
}
```

The flag accepts a schema string, a path to a `.json` schema file, or a primitive type name (`string`, `number`, `integer`, `boolean`). Read the parsed value from `structured_output`:

```bash
agy -p "Parse the semantic version string v2.14.3 into an object with integer fields major, minor, and patch." \
  --output-format json \
  --json-schema '{"type":"object","properties":{"major":{"type":"integer"},"minor":{"type":"integer"},"patch":{"type":"integer"}},"required":["major","minor","patch"]}' \
  | jq '.structured_output'
```

### Streaming JSON

Set `--output-format stream-json` to emit one JSON object per line (NDJSON) as the run progresses. Use this format to observe tool calls and token usage in real time.

```bash
agy -p "In one sentence, what is a git rebase?" --output-format stream-json
```

The stream begins with one `init` event, followed by any number of `step_update` events, and ends with one `result` event (the `cwd` and `tools` array are abbreviated in the following example):

```json
{"event":"init","conversation_id":"c3b66b04-872b-4fbe-a3a4-058a026ef20a","init":{"cwd":"/home/user/project","tools":["ask_permission","run_command","write_to_file","..."],"permission_mode":"request-review"}}
{"event":"step_update","step_update":{"conversation_id":"c3b66b04-872b-4fbe-a3a4-058a026ef20a","step_index":0,"state":"DONE","step_type":"user_input"}}
{"event":"step_update","step_update":{"conversation_id":"c3b66b04-872b-4fbe-a3a4-058a026ef20a","step_index":3,"state":"DONE","step_type":"agent_response","text_delta":"Git rebase destructively rewrites a branch's commit history by systematically detaching its unique commits and sequentially reapplying them onto a new base commit.\n","duration_seconds":6.28,"usage":{"input_tokens":10302,"output_tokens":582,"thinking_tokens":551,"cache_read_tokens":8113,"total_tokens":10884}}}
{"event":"step_update","step_update":{"conversation_id":"c3b66b04-872b-4fbe-a3a4-058a026ef20a","step_index":4,"state":"DONE","step_type":"checkpoint","duration_seconds":0.53,"usage":{"input_tokens":116,"output_tokens":7,"thinking_tokens":0,"cache_read_tokens":0,"total_tokens":123}}}
{"event":"result","result":{"conversation_id":"c3b66b04-872b-4fbe-a3a4-058a026ef20a","status":"SUCCESS","response":"Git rebase destructively rewrites a branch's commit history by systematically detaching its unique commits and sequentially reapplying them onto a new base commit.\n","duration_seconds":6.88,"num_turns":1,"usage":{"input_tokens":10418,"output_tokens":589,"thinking_tokens":551,"cache_read_tokens":8113,"total_tokens":11007}}}
```

When the response streams in chunks, the `agent_response` step emits one or more `ACTIVE` events carrying partial `text_delta` fragments before its final `DONE`; short responses like this one arrive in a single `DONE`.

Every line is an event object whose `event` field names its type:

| `event` | Payload key | Emitted |
| --- | --- | --- |
| `init` | `init` | Once, at stream start |
| `step_update` | `step_update` | For each step transition or text delta |
| `result` | `result` | Once, at the end (same shape as `json`) |

The `init` payload records the run configuration. `model` and `agent` appear only when set with `--model` or `--agent`; `permission_mode` is `request-review` by default (and `always-proceed` under `--dangerously-skip-permissions`):

| Field | Type | Description |
| --- | --- | --- |
| `cwd` | string | Working directory |
| `tools` | string\[\] | Names of all available tools |
| `permission_mode` | string | Effective permission mode |
| `model` | string | Model in use, when overridden |
| `agent` | string | Active agent, when overridden |
| `json_schema` | object | Enforced schema, when set with `--json-schema` |

Each `step_update` payload describes one step. Observed `step_type` values include `user_input`, `agent_response`, `tool`, and `checkpoint`; `state` is `ACTIVE` while a step runs and `DONE` when it finishes:

| Field | Type | Description |
| --- | --- | --- |
| `conversation_id` | string | ID of the conversation |
| `step_index` | number | Zero-based index of the step |
| `state` | string | `ACTIVE` or `DONE` |
| `step_type` | string | Step category, for example `agent_response` or `tool` |
| `tool_name` | string | Canonical tool name, on tool steps |
| `text_delta` | string | Incremental response text |
| `duration_seconds` | number | Step duration, when known |
| `usage` | object | Per-step token usage, when known |
| `tool_info` | object | Tool invocation details |
| `subagent_info` | object | Subagent invocation details |

#### Tool calls in the stream

On tool steps, `tool_info` carries the call and its result. This is a real tool step from a run that executed `echo hello_headless_demo`:

```json
{"event":"step_update","step_update":{"conversation_id":"edb1c8c1-50ba-4f3f-87eb-412d0e9d47c3","step_index":4,"state":"DONE","step_type":"tool","tool_name":"run_command","duration_seconds":0.07,"tool_info":{"name":"run_command","parameters":{"CommandLine":"echo hello_headless_demo"},"output":"hello_headless_demo\r\n"}}}
```

`tool_info` holds `name`, `parameters`, `output`, and—when the tool fails—an `error` object with `type` and `message`. Steps that spawn subagents carry `subagent_info` instead, listing each subagent under `subagents` (with `type_name`, `role`, `conversation_id`, `log_uri`, and `workspace_uris`).

#### Structured output in the stream

With `--json-schema`, the schema applies to the terminal `result` event, which carries the same `structured_output` and `json_schema` fields as the `json` envelope.

## Parse output with jq

`stdout` is machine-readable, so `jq` extracts what you need.

Get the response text from a JSON run:

```bash
agy -p "Name three popular version control systems, comma-separated." --output-format json | jq -r '.response'
```

```text
Git, Subversion, Mercurial.
```

Concatenate streaming text as it arrives:

```bash
agy -p "Explain what a merge conflict is in two sentences." --output-format stream-json \
  | jq -j 'select(.event=="step_update") | .step_update.text_delta // empty'
```

Read token usage from the terminal `result` event:

```bash
agy -p "In one sentence, what is a git rebase?" --output-format stream-json \
  | jq 'select(.event=="result") | .result.usage'
```

> **Tip:** Use `jq -j` (join output) when concatenating `text_delta` fragments so `jq` doesn’t insert newlines between them.

## Continue a conversation

Headless runs are stateless by default. Resume prior context with `--continue` (`-c`) for the most recent conversation, or `--conversation` with an ID from a previous run’s `conversation_id`:

```bash
# Continue the most recent conversation.
agy -p "Now explain your previous answer in more detail" --continue

# Resume a specific conversation by ID.
agy -p "Summarize what we discussed" --conversation 055a398f-db14-4c5f-abbb-1bf03f8120a7
```

Each of these starts a new process. To run multiple turns inside one process, refer to [Stream prompts from stdin](#stream-prompts-from-stdin).

## Stream prompts from stdin

Use `--input-format stream-json` to maintain a single, continuous conversation process, feeding it prompts one by one on standard input (stdin). Each prompt executes a full turn and emits its own `result` event.

This approach is ideal for applications that dynamically determine the next prompt based on the previous answer. Because the process only starts once, subsequent turns skip startup overhead and reuse the warmed-up conversation. This makes it significantly faster than running repeated commands with `--continue`.

> **Note:** `--input-format stream-json` requires `--output-format stream-json`. In a streaming session, the CLI emits one `result` event per turn.

### Send a prompt

Write one JSON object per line to `stdin`. The `event` key specifies the message type (matching the output stream format). A prompt is represented as a `user` event with a `message`:

```json
{ "event": "user", "message": { "content": "Reply with exactly the word: apple. Nothing else." } }
```

You can pipe multiple prompts into a single session:

```bash
printf '%s\n' \
  '{"event":"user","message":{"content":"Reply with exactly the word: apple. Nothing else."}}' \
  '{"event":"user","message":{"content":"What word did I ask you to reply with in my previous message? Answer with just that word."}}' \
  | agy --input-format stream-json --output-format stream-json
```

The `content` field accepts either a standard string or a list of text blocks. The following two formats are equivalent:

```json
{ "event": "user", "message": { "content": "Reply with exactly: banana" } }
{ "event": "user", "message": { "content": [{ "type": "text", "text": "Reply with exactly: banana" }] } }
```

`text` is the only supported block type. Submitting any other block type ends the session with an error message rather than silently dropping the block. This ensures the agent never answers a prompt you didn’t explicitly send.

### Read the results

The output stream works as follows:

1.  Opens with a single `init` event.
2.  Emits a series of `step_update` events for the active turn.
3.  Concludes the turn with a final `result` event.

This example shows the output from the two-prompt Bash command in the previous section (with the `init` payload abbreviated):

```json
{"event":"init","conversation_id":"9ec58bfd-4d67-4f5e-83a5-9d907e9c6b1f","init":{"cwd":"/home/user/project","tools":["ask_permission","run_command","write_to_file","..."],"permission_mode":"request-review"}}
{"event":"step_update","step_update":{"conversation_id":"9ec58bfd-4d67-4f5e-83a5-9d907e9c6b1f","step_index":0,"state":"DONE","step_type":"user_input"}}
{"event":"step_update","step_update":{"conversation_id":"9ec58bfd-4d67-4f5e-83a5-9d907e9c6b1f","step_index":2,"state":"ACTIVE","step_type":"agent_response","text_delta":"apple"}}
{"event":"step_update","step_update":{"conversation_id":"9ec58bfd-4d67-4f5e-83a5-9d907e9c6b1f","step_index":2,"state":"DONE","step_type":"agent_response","text_delta":"\n","duration_seconds":1.169607627,"usage":{"input_tokens":30384,"output_tokens":4,"thinking_tokens":0,"cache_read_tokens":0,"total_tokens":30388}}}
{"event":"result","result":{"conversation_id":"9ec58bfd-4d67-4f5e-83a5-9d907e9c6b1f","status":"SUCCESS","response":"apple\n","duration_seconds":1.427806958,"num_turns":1,"usage":{"input_tokens":30384,"output_tokens":4,"thinking_tokens":0,"cache_read_tokens":0,"total_tokens":30388}}}
{"event":"step_update","step_update":{"conversation_id":"9ec58bfd-4d67-4f5e-83a5-9d907e9c6b1f","step_index":3,"state":"DONE","step_type":"user_input"}}
{"event":"step_update","step_update":{"conversation_id":"9ec58bfd-4d67-4f5e-83a5-9d907e9c6b1f","step_index":4,"state":"DONE","step_type":"agent_response","text_delta":"apple\n","duration_seconds":0.895679386,"usage":{"input_tokens":278,"output_tokens":4,"thinking_tokens":0,"cache_read_tokens":30214,"total_tokens":282}}}
{"event":"result","result":{"conversation_id":"9ec58bfd-4d67-4f5e-83a5-9d907e9c6b1f","status":"SUCCESS","response":"apple\n","duration_seconds":2.548755756,"num_turns":2,"usage":{"input_tokens":30662,"output_tokens":8,"thinking_tokens":0,"cache_read_tokens":30214,"total_tokens":30670}}}
```

The second turn answers `apple` from the first turn’s context. Notice that a single `conversation_id` tracks the entire session, and `init` is only sent once.

When parsing the result object, keep in mind that the response text applies only to the current turn, while metadata counters track the cumulative session:

| Field | Scope |
| --- | --- |
| `response` | The turn that emitted it |
| `num_turns` | Cumulative over the session |
| `usage` | Cumulative over the session |
| `duration_seconds` | Cumulative over the session |

To filter and only view the final responses, you can pipe the output through `jq`:

```bash
printf '%s\n' \
  '{"event":"user","message":{"content":"Reply with exactly: one"}}' \
  '{"event":"user","message":{"content":"Reply with exactly: two"}}' \
  | agy --input-format stream-json --output-format stream-json \
  | jq -r 'select(.event=="result") | "\(.result.num_turns): \(.result.response)"'
```

```text
1: one

2: two
```

### Drive a session programmatically

Instead of passing all prompts up front, you can hold the `stdin` pipe open in a script. This allows your application to evaluate the model’s answer before submitting the next prompt.

> **Tip:** You can read `stdout` line by line and dispatch logic based on the `event` field. Wait until you receive the `result` event for the current prompt before writing the next one.

For example:

```python
import json
import subprocess

proc = subprocess.Popen(
    ["agy", "--input-format", "stream-json", "--output-format", "stream-json"],
    stdin=subprocess.PIPE,
    stdout=subprocess.PIPE,
    text=True,
    bufsize=1,
)


def ask(prompt):
    """Send one prompt and return the response for that turn."""
    message = {"event": "user", "message": {"content": prompt}}
    proc.stdin.write(json.dumps(message) + "\n")
    proc.stdin.flush()
    for line in proc.stdout:
        event = json.loads(line)
        if event["event"] == "result":
            return event["result"]["response"]


first = ask("Name one popular version control system. Answer with one word.")
print(ask(f"Name a competitor to {first.strip()}. Answer with one word."))

proc.stdin.close()
proc.wait()
```

### End a session

To close a session gracefully, close `stdin`. The process exits after the input pipe is closed and the current turn completes. If an application writes a final prompt and immediately closes the pipe, it still receives the final `result` before the process terminates.

Clean sessions exit with `0`, which matches the standard headless mode behavior.

### Unsupported messages

To prevent unpredictable behavior, the CLI validates inputs. If it encounters a malformed or unsupported message, it responds as described in the following table:

| Input | Result | Exit |
| --- | --- | --- |
| Unrecognized `event` name | Skipped: warning logged to `stderr` | — |
| `control_request` or `control_response` events | `ERROR` result, session ends | `2` |
| Slash command handled by the CLI such as `/model` | `ERROR` result, session ends | `2` |
| Message missing the `event` field | `ERROR` result, session ends | `1` |
| Invalid JSON line | `ERROR` result, session ends | `1` |
| Content block type other than `text` | `ERROR` result, session ends | `1` |

Unrecognized `event` names are safely skipped with a warning. This ensures that applications built against newer versions of the streaming protocol don’t crash when running on older CLI versions:

```text
warning: ignoring unsupported stream input message event "future_thing"
```

For all other errors, the session terminates immediately. Any turns that previously completed retain their `result` events, but the malformed input line aborts the remainder of the session.

Slash commands that the CLI can respond to directly (such as `/model` and `/usage`) produce a text report rather than a standard event stream. A streaming session can’t use these types of slash commands. For example:

```json
{ "event": "result", "result": { "conversation_id": "4fae3a70-409d-42a4-86ea-9de206a49ff4", "status": "ERROR", "response": "", "error": "/model is answered by the CLI itself and is unavailable with --input-format stream-json; run it as its own --print /model invocation", "duration_seconds": 0, "num_turns": 0, "usage": { "input_tokens": 0, "output_tokens": 0, "thinking_tokens": 0, "cache_read_tokens": 0, "total_tokens": 0 } } }
```

### Common mistakes

| Mistake | Why it fails | How to fix it |
| :-- | :-- | :-- |
| **Pairing with `--output-format json` or `text`** | Those formats only emit a single output envelope when the process exits, causing every turn except the last one to be lost. | Always use `--output-format stream-json` with this input mode. |
| **Passing a prompt with the `-p` flag** | Streaming mode exclusively listens for prompts on `stdin`. Any prompt passed through a command-line flag is dropped. | Send the prompt into `stdin` as a `user` message instead. |
| **Sending `/model` or `/usage` into the stream** | The CLI handles these commands internally outside of the event stream, breaking the JSON flow. | Run `agy -p /model` as an entirely separate, standalone command. |
| **Treating `num_turns` as a per-turn count** | Metadata counters (like turns, duration, and usage) track the entire cumulative session, not just the active turn. | Use the `response` field to get the text for the current turn. |
| **Waiting for the process to exit before reading `stdout`** | The session stays open indefinitely until `stdin` is closed. If your script waits for an exit signal, it hangs. | Read the events line-by-line as they arrive, and manually close `stdin` when finished. |

## Select a model, effort, or agent

List the available model slugs, then pin one for the run:

```bash
agy models
```

```plaintext
gemini-4-argon-high       Gemini 4 Argon (High)
gemini-4-argon-medium     Gemini 4 Argon (Medium)
gemini-3.8-flash-high     Gemini 3.8 Flash (High)
gemini-3.8-flash-medium   Gemini 3.8 Flash (Medium)
gemini-3.7-flash-high     Gemini 3.7 Flash (High)
gemini-3.7-flash-medium   Gemini 3.7 Flash (Medium)
gemini-3.6-flash-high     Gemini 3.6 Flash (High)
gemini-3.6-flash-medium   Gemini 3.6 Flash (Medium)
gemini-3.1-pro-high       Gemini 3.1 Pro (High)
...
```

```bash
# Pin a model by slug.
agy -p "Reverse the string antigravity." --model gemini-3.8-flash-medium

# Set reasoning effort (low, medium, or high).
agy -p "Outline a plan to add caching to this service." --effort high

# Select an agent (list them with `agy agents`).
agy -p "Review this function for edge cases." --agent <agent-name>
```

Unlike the interactive UI, headless mode doesn’t silently fall back when `--model` names an unknown model. It exits non-zero with an `ERROR` status so a pinned pipeline fails loudly instead of running the wrong model.

## Permissions in headless mode

There is no interactive prompt in headless mode, so tools that would normally ask for confirmation are handled by policy.

By default, the CLI respects the execution and permission modes in your settings. In `default` mode, actions such as shell commands default to **Ask**; in `auto` mode, workspace file edits and sandboxed or safe, reversible commands run automatically, while risky or irreversible actions still require approval. Any tool action that requires approval it can’t obtain in headless mode is soft-denied: the run continues, exits `0`, and prints a notice to `stderr` naming the tool and how to allow it.

Grant a tool ahead of time by adding an `action(target)` rule under `permissions.allow` in `~/.gemini/antigravity-cli/settings.json`:

```json
{
  "permissions": {
    "allow": [
      "command(git)",
      "command(regex:npm run (build|lint|test))",
      "write_file(src/)"
    ]
  }
}
```

To auto-approve every tool for a run, pass `--dangerously-skip-permissions`:

```bash
agy -p "Run the test suite and report failures" --dangerously-skip-permissions
```

> **Warning:** `--dangerously-skip-permissions` approves all tool calls, including file writes and command execution. Prefer scoped `permissions.allow` rules unless you fully trust the prompt and environment. Refer to [Permissions](/docs/cli/permissions) for the full rule syntax.

## Handle exit codes and errors

A successful run exits `0`. A run that fails to produce a response exits non-zero and writes the reason to `stderr`. In `json` and `stream-json` modes, the failure also appears in the `status` and `error` fields.

For example, pinning an unknown model exits `1` and returns an error envelope:

```bash
agy -p "hi" --model does-not-exist-model --output-format json; echo "exit=$?"
```

```json
{"conversation_id":"","status":"ERROR","response":"","error":"invalid model selection (--model \"does-not-exist-model\" --effort \"\"): model does-not-exist-model is not recognized as a known model or custom model in settings\nAvailable models:\n  Gemini 3.6 Flash (High)\n  ...","duration_seconds":0,"num_turns":0,"usage":{"input_tokens":0,"output_tokens":0,"thinking_tokens":0,"cache_read_tokens":0,"total_tokens":0}}
```

```text
exit=1
```

The `status` field reports the terminal state of the run:

| Status | Meaning |
| --- | --- |
| `SUCCESS` | The run completed and produced a response |
| `ERROR` | The run ended with an error |
| `CANCELED` | The run was canceled |
| `INTERRUPTED` | The run was interrupted (for example, `SIGINT`) |
| `INVALID` | The run reached an invalid state |
| `WAITING` | The run ended while waiting on input |
| `RUNNING` | The run did not reach a terminal state |

By default, a run has no time limit and waits until the turn completes. Set a limit with `--print-timeout`:

```bash
agy -p "Summarize the design tradeoffs of optimistic locking." --print-timeout 15m
```

## Flag reference

| Flag | Default | Description |
| --- | --- | --- |
| `-p`, `--print`, `--prompt` | — | Run a single prompt non-interactively and print the response |
| `--output-format` | `text` | Output format: `text`, `json`, or `stream-json` |
| `--input-format` | `text` | Input format: `text` or `stream-json`; reads prompts on stdin |
| `--json-schema` | — | Schema string or file path to enforce structured output |
| `--model` | — | Model slug for this run (refer to `agy models`) |
| `--effort` | — | Reasoning effort: `low`, `medium`, or `high` |
| `--agent` | — | Agent for this run (refer to `agy agents`) |
| `--continue`, `-c` | `false` | Continue the most recent conversation |
| `--conversation` | — | Resume a conversation by ID |
| `--dangerously-skip-permissions` | `false` | Auto-approve all tool permission requests |
| `--print-timeout` | `0s` | Maximum time to wait for a response (`0s` means no limit) |
| `--sandbox` | `false` | Run with terminal sandbox restrictions enabled |

## Example: run the agent in CI

Fail the job on error and save the response:

```bash
#!/usr/bin/env bash
set -euo pipefail

result=$(agy -p "Name three popular version control systems, comma-separated." \
  --output-format json \
  --print-timeout 10m)

status=$(echo "$result" | jq -r '.status')
if [[ "$status" != "SUCCESS" ]]; then
  echo "Agent run failed: $(echo "$result" | jq -r '.error')" >&2
  exit 1
fi

echo "$result" | jq -r '.response' > result.txt
```

## Next steps

Explore the following guides to learn more about CLI capabilities:

*   **[Prompting and interaction](/docs/cli/prompting)**: Write effective prompts for the agent.
*   **[Permissions](/docs/cli/permissions)**: Configure allow, deny, and ask rules.
*   **[Background tasks and subagents](/docs/cli/subagents)**: Delegate work to specialized agents.
*   **[Reference](/docs/cli/reference)**: Full command and flag reference.