# Agent mode (ACP)

> Run grok agent stdio as an Agent Client Protocol server for IDEs and custom clients; JSON-RPC session lifecycle, streaming, permissions, and options shared with agent subcommands.

- Repository: xai-org/grok-build
- GitHub: https://github.com/xai-org/grok-build
- Human docs: https://grok-wiki.com/public/docs/xai-org-grok-build-90205de50458
- Complete Markdown: https://grok-wiki.com/public/docs/xai-org-grok-build-90205de50458/llms-full.txt

## Source Files

- `crates/codegen/xai-grok-pager/docs/user-guide/15-agent-mode.md`
- `crates/codegen/xai-acp-lib/src/lib.rs`
- `crates/codegen/xai-acp-lib/src/gateway.rs`
- `crates/codegen/xai-grok-shell/src/session/acp_session.rs`
- `crates/codegen/xai-grok-shell/src/session/acp_types.rs`
- `crates/codegen/xai-grok-pager/src/app/cli.rs`

---

---
title: "Agent mode (ACP)"
description: "Run grok agent stdio as an Agent Client Protocol server for IDEs and custom clients; JSON-RPC session lifecycle, streaming, permissions, and options shared with agent subcommands."
---

`grok agent stdio` runs the Grok agent as a long-lived **Agent Client Protocol (ACP)** server. Clients exchange **newline-delimited JSON-RPC 2.0** messages over the process **stdin** (requests/notifications) and **stdout** (responses/notifications). Unlike `grok -p` / `--single` (one prompt, print, exit), agent mode keeps the process up for many sessions and turns until the client closes the transport.

```mermaid
sequenceDiagram
  participant Client as ACP client<br/>(IDE / SDK / custom)
  participant Stdio as grok agent stdio
  participant Agent as Agent + SessionActor
  participant Tools as Tools / MCP / FS

  Client->>Stdio: initialize
  Stdio-->>Client: InitializeResponse (capabilities, models, authMethods)
  Client->>Stdio: authenticate (optional / as required)
  Client->>Stdio: session/new { cwd, mcpServers, _meta }
  Stdio->>Agent: create SessionActor
  Agent-->>Client: sessionId + modes/models
  Client->>Stdio: session/prompt
  loop Streamed turn
    Agent-->>Client: session/update (message / thought / tool_call)
    Agent->>Client: session/request_permission (when needed)
    Client-->>Agent: allow / deny / cancel
    Agent->>Tools: execute approved tools
  end
  Agent-->>Client: PromptResponse (stopReason)
  Client->>Stdio: session/cancel (optional, mid-turn)
```

## When to use agent mode

| Surface | Command | Lifetime | Best for |
| --- | --- | --- | --- |
| Interactive TUI | `grok` | User-driven terminal UI | Day-to-day coding in a terminal |
| Headless single-shot | `grok -p` / `--single` | One prompt → exit | Scripts, CI, eval harnesses |
| **ACP agent (stdio)** | `grok agent stdio` | Persistent process | IDEs, editors, ACP SDKs, custom clients |
| WebSocket server | `grok agent serve` | Persistent listener | Remote clients over `ws://` |
| Relay headless | `grok agent headless` | Persistent outbound WS | Web UIs via a shared relay |
| Shared leader | `grok agent leader` | Multi-client backend | Multiple followers sharing one agent |

Provider and endpoint settings stay portable: model selection, BYOK / OpenAI-compatible bases, and MCP registration use the same config layers as other surfaces (`config.toml`, env, CLI flags). Agent mode does not require a specific third-party host; any ACP client that speaks the protocol can attach.

## Start the stdio server

```bash
grok agent stdio
```

Options for `grok agent` go **before** the mode name. The `stdio` mode itself takes no extra flags:

```bash
grok agent --model grok-build --always-approve stdio
grok agent --agent-profile ./my-agent.md --plugin-dir /path/to/plugin stdio
```

<Check>
The agent writes JSON-RPC only on **stdout**. Diagnostics and human messages use **stderr** (for example `--plugin-dir` skip warnings, serve startup banner). Do not mix client parsers with stderr.
</Check>

### Prerequisites

- Installed `grok` on `PATH` (see [Installation](/installation)).
- Auth already present (`grok login`, device flow, or `XAI_API_KEY` / stored credentials in `~/.grok/auth.json`) unless the client drives `authenticate` after `initialize`.
- Working directory meaningful for the workspace the client will pass as `session/new` `cwd`.

### Verification

1. Spawn `grok agent stdio`.
2. Send an `initialize` request with `protocolVersion` and client capabilities.
3. Expect an `InitializeResponse` whose `_meta` includes `"grokShell": true` when talking to a grok-shell agent, plus `modelState`, `availableCommands`, and `authMethods`.
4. Create a session with `session/new`, then `session/prompt`; observe `session/update` notifications before the final prompt result.

## Agent CLI surface

### Modes (`AgentCmd`)

| Mode | Command | Role |
| --- | --- | --- |
| **stdio** | `grok agent stdio` | NDJSON ACP on stdin/stdout (primary IDE integration) |
| **headless** | `grok agent headless` | Outbound Grok WebSocket relay (`--grok-ws-url`, `--grok-ws-origin`) |
| **serve** | `grok agent serve` | Local WebSocket server (default bind `127.0.0.1:2419`) |
| **leader** | `grok agent leader` | Shared leader process for multi-client attach |
| *(omit mode)* | `grok agent` | Same path as **headless** (defaults into the headless runner) |

### Flags on `grok agent` (before the mode)

| Flag | Effect |
| --- | --- |
| `-m, --model <MODEL>` | Default model override for sessions this process creates |
| `--reasoning-effort` / `--effort <EFFORT>` | Reasoning effort override |
| `--always-approve` (`--yolo`) | Seed sessions with always-approve (YOLO) tool permissions |
| `--agent-profile <PATH>` | Load an agent definition file for this process |
| `--plugin-dir <DIR>` (repeatable) | Process-local plugins; always trusted (hooks/MCP activate without prompt). Canonicalized; non-directories skipped with a stderr warning |
| `--reauth` / `--reauthenticate` | Run authentication before start (used by headless path) |
| `--leader` / `--no-leader` | Prefer or force non-shared agent (conflicts with each other). Defaults also come from `[cli] use_leader` |
| `--cli-chat-proxy-base-url` | Override CLI chat proxy base URL |
| `--xai-api-base-url` | Override public xAI API base URL |
| Nested WS URL args | `--grok-ws-url`, `--grok-ws-origin` (headless / serve / leader) |

### `serve` options

| Flag / env | Default | Notes |
| --- | --- | --- |
| `--bind <ADDR>` | `127.0.0.1:2419` | Listen address |
| `--secret <TOKEN>` or `GROK_AGENT_SECRET` | Auto-generated (12 chars) if omitted | Client auth; printed on stderr at startup as `ws://{bind}/ws?server-key=...` |
| `--remote <URL>` | — | Proxy mode remote agent URL |

### Top-level flags that still apply to `grok agent`

When dispatching `Command::Agent`, the binary also threads these **top-level** `PagerArgs` into the agent process:

| Flag | Effect on agent |
| --- | --- |
| `--permission-mode <MODE>` | Launch permission mode; `bypassPermissions` / `always-approve` map to YOLO |
| `--trust` | Grant folder trust for current cwd |
| `--disable-web-search` | Disable web search / fetch tools in resolved agent config |
| `--no-auto-update` | Skip auto-update checks for this run |

Top-level `--leader` / `--no-leader` (pager TUI) **do not** apply to the agent subcommand; use `grok agent --leader` / `--no-leader` instead.

### Permission mode values

`--permission-mode` accepts:

`default` · `acceptEdits` · `auto` · `dontAsk` · `bypassPermissions` · `plan`

Launch resolution:

- Explicit `--permission-mode` wins for the launch.
- Otherwise `--always-approve` / `--yolo` enables always-approve.
- Managed policy can **block** always-approve (`disable_bypass_permissions_mode` / requirements); the CLI prints a warning and does not enable YOLO.

Full tool-authorization pipeline (hooks, allow/deny, remembered grants, sandbox) is documented under [Permissions and safety](/permissions-and-safety).

### Leader-backed stdio

When leader mode is active (`--leader` or `[cli] use_leader = true` and policy allows it), `grok agent stdio` becomes a **thin bridge**: stdin lines go to the leader over IPC; stdout mirrors leader messages. On reconnect it may re-play initialize/session state and emit `x.ai/leader_reconnected`.

`--plugin-dir` is **ignored** in leader mode (plugins must load on the leader process). Use `--no-leader` for per-process plugins.

## Transport and I/O contract

- **Framing:** one JSON-RPC message per line (`\n`-delimited NDJSON).
- **Max line size:** 64 MiB (hard cap in the line-buffered reader).
- **Stdin ownership:** a dedicated OS thread reads stdin so persistent clients (stdin stays open) work reliably; Windows additionally detaches the process stdin handle to avoid lock deadlocks with stray `stdin()` reads.
- **Internal inject path:** stdio mode multiplexes client lines with internal reloads (for example skills watcher) through a simplex buffer so injected control messages do not split mid-line.
- **Do not** write logs to stdout from wrappers; that corrupts the protocol.

Environment hooks useful to integrators:

| Variable | Role |
| --- | --- |
| `GROK_CLIENT_VERSION` | Logged early for auth/diagnostics when a desktop host spawns the agent |
| `GROK_AGENT_METADATA` | Optional JSON object merged into `InitializeResponse.meta.metadata` |
| `GROK_AGENT_SECRET` | Default secret for `agent serve` |
| `GROK_AGENT` | Named agent selection (below CLI `--agent-profile` / session `_meta.agentProfile`) |
| `XAI_API_KEY` | API-key auth path (same as other surfaces) |

## JSON-RPC session lifecycle

### Agent methods (client → agent)

Core ACP methods handled by the agent side:

| Method | Kind | Purpose |
| --- | --- | --- |
| `initialize` | request | Protocol version, client capabilities → agent capabilities + meta |
| `authenticate` | request | Auth method id (OIDC / API key / provider methods as advertised) |
| `session/new` | request | Create session (`cwd`, `mcpServers`, optional `_meta`) |
| `session/load` | request | Load / resume a persisted session |
| `session/prompt` | request | Submit user content blocks; streams updates until final result |
| `session/cancel` | notification | Cancel the in-flight turn for a session |
| `session/set_mode` | request | Change session mode |
| `session/set_model` | request | Change session model |
| `ext_method` / `ext_notification` | request / notification | Vendor extensions (Grok uses `x.ai/…`) |

### Client reverse methods (agent → client)

While a turn runs, the agent may call **into** the client:

| Method | Purpose |
| --- | --- |
| `session/request_permission` | Approve or deny a tool invocation |
| `fs/read_text_file` / `fs/write_text_file` | Client-side file ops when FS capabilities are enabled |
| Terminal methods | `create` / `output` / `release` / `wait_for_exit` / `kill` (when terminal capability is on) |
| `session/update` (notification) | Streamed turn progress |
| Client `ext_method` / `ext_notification` | e.g. client hook gate `x.ai/hooks/run` |

Clients that cannot implement a reverse method must advertise limited capabilities on `initialize` and handle `MethodNotFound` where applicable (for example some hosts reject `WaitForTerminalExit` and poll instead).

### `initialize` response (agent capabilities)

Successful initialize advertises roughly:

- **Protocol:** ACP v1
- **Capabilities:** `loadSession: true`, prompt `embeddedContext: true`, MCP over HTTP and SSE
- **Capability meta:** `x.ai/fs_notify`, blocking client hooks for `PreToolUse` with `deny` decisions
- **Response `_meta` (selected fields):** `grokShell`, `defaultAuthMethodId`, `agentVersion`, `agentId`, `agentInstanceId`, `hostname`, `currentWorkingDirectory`, `modelState`, `mcpServers`, `availableCommands`, `cancelRewind`, `sessionRecap`, optional `metadata` from `GROK_AGENT_METADATA`

Auth methods in the response drive whether the client must call `authenticate` or can proceed with cached credentials / API key.

### `session/new` and `session/load`

**Request (shape):**

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "session/new",
  "params": {
    "cwd": "/path/to/project",
    "mcpServers": [],
    "_meta": {
      "rules": "Extra rules appended to the system prompt",
      "systemPromptOverride": "Replace the system prompt entirely",
      "agentProfile": "grok-build",
      "yoloMode": false,
      "autoMode": false,
      "x.ai/hooks": []
    }
  }
}
```

| `_meta` field | Meaning |
| --- | --- |
| `rules` | Extra rules appended to the system prompt |
| `systemPromptOverride` | Full system prompt replacement (also re-applied on cold load when present) |
| `agentProfile` | String name **or** JSON object definition for the agent persona/toolset |
| `yoloMode` | Seed always-approve for this session (leader can inject this for capable followers) |
| `autoMode` | Seed classifier auto-permission mode (ignored when yolo is on) |
| `x.ai/hooks` | Client-registered hooks (see below) |

**Agent profile resolution order** (highest wins):

1. Session `_meta.agentProfile`
2. CLI `--agent-profile`
3. `[agent]` in `config.toml`
4. `GROK_AGENT` env
5. Built-in default agent

`mcpServers` from the client are merged with managed/project MCP config for that `cwd`.

### Prompt turn and streaming

`session/prompt` accepts a `sessionId` and `prompt` content blocks (text and other ACP block types the client supports). During the turn the agent emits **`session/update`** notifications. Standard `sessionUpdate` values clients should handle:

| `sessionUpdate` | Content |
| --- | --- |
| `agent_message_chunk` | Incremental assistant text |
| `agent_thought_chunk` | Incremental reasoning / thought text |
| `tool_call` | New tool invocation (title, kind, status, input; may include `_meta` such as `x.ai/tool`) |
| `tool_call_update` | Status/result updates for an in-flight tool |
| `plan` | Structured plan payload when plan mode is active |

The prompt **response** carries a `stopReason` such as `end_turn` or `cancelled` (cancel path). After cancel, clients should treat the turn as finished and may start a new `session/prompt`.

Grok also streams **vendor** updates on `_x.ai/session/update` / related methods for subagents, goals, hook annotations, queue changes, and similar. Treat unknown `sessionUpdate` values as forward-compatible (ignore or log).

### Permissions during a turn

Without always-approve, tool use goes through:

1. PreToolUse hooks (file hooks + client `x.ai/hooks/run` when registered)
2. Allow / deny rules and remembered grants
3. `session/request_permission` to the client when the policy is **ask**
4. Sandbox profile constraints for the child process

With `--always-approve` / `yoloMode` / `bypassPermissions` (and no managed block), the agent auto-approves tool executions that policy still allows.

Client hooks at `session/new` (`_meta["x.ai/hooks"]`):

- **PreToolUse:** reverse **request** `x.ai/hooks/run` — `deny` blocks the tool; default timeout **30s** (fails open on timeout/malformed reply)
- **Other events:** fire-and-forget notification `x.ai/hooks/event`

## Extension methods (`x.ai/…`)

Beyond base ACP, the agent implements many **extension** methods under the `x.ai/` prefix. Categories (non-exhaustive; discover what the running agent implements via initialize meta and method errors):

| Category | Examples |
| --- | --- |
| Filesystem | `x.ai/fs/*` list/exists/read/write; notifications `x.ai/fs/index`, `x.ai/fs/index/delta`, `x.ai/fs_notify` |
| Git / worktree | `x.ai/git/*`, `x.ai/git/worktree/*` (create, remove, apply, list, gc, resume helpers) |
| Search | `x.ai/search/*` (fuzzy/content); status notifications |
| Terminal | `x.ai/terminal/*` |
| Session admin | `x.ai/session/info`, `close`, `list`, `fork`, `repair`, `update_mcp_servers`, `search` |
| Conversation | compact, rewind / rewind points, prompt history (see types under shell session ACP types) |
| Hooks / plugins / MCP | `x.ai/hooks/*`, `x.ai/plugins/*`, `x.ai/mcp/list`, marketplace actions |
| Memory | `x.ai/memory/flush`, `x.ai/memory/rewrite` |
| Auth helpers | `x.ai/auth/*` (URL / device code flows for interactive clients) |
| Telemetry / feedback | `x.ai/log`, `x.ai/feedback`, `x.ai/recap` (when advertised) |
| Leader | `x.ai/leader_reconnected`, version mismatch notifications |

Extension methods are SpaceXAI/Grok-specific and evolve across releases. Prefer capability meta and error handling over hard-coding a frozen list.

## Architecture (stdio process)

```text
┌──────────────────────────┐     NDJSON JSON-RPC      ┌──────────────────────────────┐
│ ACP client               │ ───────────────────────► │ grok agent stdio             │
│ (IDE, SDK, custom host)  │ ◄─────────────────────── │                              │
└──────────────────────────┘     stdout / reverse RPC │  xai-acp-lib gateway         │
                                                      │    ↕                         │
                                                      │  Agent (mvp_agent)           │
                                                      │    ├─ session registry       │
                                                      │    ├─ SessionActor per id    │
                                                      │    ├─ tools + permissions    │
                                                      │    ├─ MCP servers            │
                                                      │    └─ auth manager           │
                                                      └──────────────────────────────┘
```

Internal crates of note:

| Crate / module | Responsibility |
| --- | --- |
| `xai-acp-lib` | Channels, gateway sender/receiver, stdin line reader, message enums |
| `xai-grok-shell` `agent::app::run_stdio_agent` | Stdio entrypoint, LocalSet, auth refresh, I/O bind |
| `mvp_agent::acp_agent` | ACP `Agent` trait: initialize, session, prompt, cancel, extensions |
| `session::acp_session` | Per-session actor: turns, tools, streaming, permissions |
| `xai-grok-pager-bin` `run_agent_command` | CLI dispatch for all agent modes + leader bridge |

## Minimal client flow

<Steps>
  <Step title="Spawn the agent">
    Start `grok agent stdio` as a child process. Keep stdin open for the whole session. Read stdout line-by-line as JSON-RPC.
  </Step>
  <Step title="Initialize and authenticate">
    Call `initialize` with your `protocolVersion` and capabilities (`fs`, `terminal` as supported). If `authMethods` require it, call `authenticate` with the chosen method id (or rely on pre-seeded credentials / API key).
  </Step>
  <Step title="Create a session">
    Call `session/new` with absolute `cwd`, any client MCP servers, and optional `_meta` (`rules`, `agentProfile`, hooks). Store `sessionId` from the result.
  </Step>
  <Step title="Prompt and stream">
    Call `session/prompt` with content blocks. Handle `session/update` until a response with `result` / `stopReason` arrives. Implement `session/request_permission` so tool calls are not stuck in ask mode.
  </Step>
  <Step title="Cancel or resume">
    Send `session/cancel` to abort a turn. Use `session/load` (or session extension helpers) to resume persisted work; use `session/set_model` / `session/set_model` as needed mid-session.
  </Step>
</Steps>

<RequestExample>
```bash
# Shell: start ACP stdio agent (IDE/SDK spawns this)
grok agent --model grok-build stdio
```
</RequestExample>

<RequestExample>
```json
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":1,"clientCapabilities":{"fs":{"readTextFile":true,"writeTextFile":true},"terminal":true}}}
```
</RequestExample>

<ResponseExample>
```json
{"jsonrpc":"2.0","id":1,"result":{"protocolVersion":1,"agentCapabilities":{"loadSession":true},"authMethods":[],"_meta":{"grokShell":true,"agentVersion":"…","modelState":{}}}}
```
</ResponseExample>

Official ACP SDKs (language-neutral protocol) are available for TypeScript (`@agentclientprotocol/sdk`), Rust (`agent-client-protocol`), Python, Go, and Kotlin. Point them at the `grok agent stdio` binary rather than re-implementing framing.

## Comparison with headless `-p`

| Concern | `grok agent stdio` | `grok -p` / headless |
| --- | --- | --- |
| Protocol | ACP JSON-RPC | Plain / JSON / streaming-json CLI output |
| Lifetime | Persistent | Single prompt (optional resume flags) |
| Permissions UX | Client implements `request_permission` | CLI allow/deny, YOLO, or non-interactive policy |
| Sessions | `session/new` + `session/load` | `--resume` / `--continue` / `--session-id` |
| Integrators | IDEs, multi-turn UIs | Scripts and CI |

Many runtime concerns (models, MCP, skills, sandbox, permissions, memory) are shared. Prefer agent mode when the host needs multi-turn streaming and interactive tool approval; prefer `-p` for fire-and-forget automation (see [Headless mode](/headless-mode)).

## Operational notes

- **Auth refresh:** stdio starts proactive token refresh and a system-power listener so refresh does not straddle suspend on interactive hosts.
- **Shutdown:** closing stdin ends the reader; the agent flushes pending handlers, closes PTYs, and allows a short grace period for upload queue drain.
- **Updates:** direct stdio (non-leader) may run non-blocking update checks in the background; stderr stays free of NDJSON.
- **Config:** same effective config as other entrypoints (`CLI > env > user config > managed/requirements > defaults`). Dump with `grok inspect` when diagnosing model or permission seeds.
- **Folder trust:** `--trust` persists trust for the current directory before the agent runs.

## Troubleshooting

| Symptom | Likely cause | What to check |
| --- | --- | --- |
| Client hangs on first request | Stdin not line-flushed or stdout mixed with logs | Ensure NDJSON lines end with `\n`; redirect logs to stderr/files |
| `initialize` never completes (Windows) | Competing stdin readers | Only the agent owns stdin; avoid spawning interactive sub-prompts on the same process stdin |
| Tools never run / hang | Unhandled `request_permission` | Implement permission responses or pass `--always-approve` / `yoloMode` (policy permitting) |
| Auth errors on first turn | No credentials / wrong method | `grok login`, `XAI_API_KEY`, or client `authenticate`; see [Authentication](/authentication) |
| Plugins missing in leader mode | `--plugin-dir` ignored | Load plugins on the leader or use `--no-leader` |
| YOLO ignored with warning | Managed policy pin | Requirements/managed config disables bypass; remove pin or use allow rules instead |
| Protocol parse errors | Multi-line or oversized payload | One JSON object per line; keep under 64 MiB |

For terminal/SSH/color issues outside ACP, see [Troubleshooting](/troubleshooting).

## Related pages

<CardGroup>
  <Card title="Overview" href="/overview">
    How TUI, headless `-p`, and ACP agent surfaces fit together.
  </Card>
  <Card title="Headless mode" href="/headless-mode">
    Single-shot `-p` runs, output formats, and CI patterns.
  </Card>
  <Card title="Permissions and safety" href="/permissions-and-safety">
    Tool authorization, permission modes, hooks, and sandbox interaction.
  </Card>
  <Card title="Sessions" href="/sessions">
    Persistence, resume/fork/compact, and session ID constraints.
  </Card>
  <Card title="MCP servers" href="/mcp-servers">
    Register stdio/HTTP MCP servers used from `session/new` and config.
  </Card>
  <Card title="CLI reference" href="/cli-reference">
    Full `grok` command and shared runtime flag inventory.
  </Card>
  <Card title="Authentication" href="/authentication">
    OAuth, device code, API keys, and credential storage.
  </Card>
  <Card title="Configure Grok" href="/configure-grok">
    config.toml precedence, feature flags, and `grok inspect`.
  </Card>
</CardGroup>
