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

# ACP — ChatCLI inside your IDE

> chatcli acp turns ChatCLI into a native IDE agent over the Agent Client Protocol: JetBrains IDEs and Zed drive the real chat/agent/coder engines with structured tool calls, live plan tracking, slash commands and native permission dialogs — no terminal emulation, no scraped output.

The **Agent Client Protocol (ACP)** is an open protocol that lets editors and IDEs host external coding agents as first-class citizens: the IDE renders the agent's reasoning, tool calls, plans and permission prompts natively, while the agent runs as a separate process speaking JSON-RPC over stdio.

`chatcli acp` is ChatCLI's ACP server. Everything you have configured in ChatCLI — providers, models, memory, contexts, skills, plugins, MCP servers — drives your IDE's AI chat.

<Info>
  What the IDE renders for agent/coder runs is fully **structured** — not a streamed terminal transcript:

  * **Thoughts** — the agent's reasoning arrives as native thought chunks (collapsible in most clients).
  * **Tool calls** — each action is a first-class tool call with a human title ("Reading: main.go"), a semantic kind (read, edit, execute, search…), live status, and the files it touches. Successful file reads show *which* file was read — never a dump of its contents into the chat.
  * **Plan** — the coder's task list streams as a live plan panel, checked off as the agent progresses.
  * **Final answer** — clean assistant prose, rendered as markdown by the IDE.
  * **Permission dialogs** — dangerous commands and policy `ask` rules pause the run and raise the IDE's native dialog with the same four choices as the terminal prompt: allow or reject, once or always.
</Info>

## Quick start

```bash theme={"system"}
# 1. Make sure chatcli works standalone first
chatcli --version

# 2. Start the ACP server (your IDE does this for you once configured)
chatcli acp
```

The process speaks newline-delimited JSON-RPC on stdin/stdout. All logging goes to the file logger — the protocol channel stays clean.

## JetBrains IDEs (IntelliJ IDEA, GoLand, WebStorm, …)

JetBrains AI Assistant hosts custom ACP agents natively (macOS and Linux; no AI subscription required for ACP agents).

<Steps>
  <Step title="Open the custom-agent configuration">
    In the **AI Chat** tool window, open the agent dropdown and choose **Add Custom Agent**. The IDE creates and opens `~/.jetbrains/acp.json`.
  </Step>

  <Step title="Register ChatCLI">
    ```json ~/.jetbrains/acp.json theme={"system"}
    {
      "default_mcp_settings": {
        "use_custom_mcp": true,
        "use_idea_mcp": false
      },
      "agent_servers": {
        "ChatCLI": {
          "command": "/usr/local/bin/chatcli",
          "args": ["acp"],
          "env": {
            "LLM_PROVIDER": "CLAUDEAI",
            "LLM_MODEL": "claude-sonnet-4-6"
          }
        }
      }
    }
    ```

    * `command` must be an **absolute path** (`which chatcli` to find it).
    * `env` is optional — with it you pin provider/model for the IDE independently of your terminal sessions; without it, ChatCLI boots with your regular `.env`/environment resolution.
  </Step>

  <Step title="Select ChatCLI and chat">
    Back in AI Chat, pick **ChatCLI** from the agent dropdown and send a prompt. Custom agents show a distinct icon.
  </Step>
</Steps>

<Note>
  `use_custom_mcp` / `use_idea_mcp` control which MCP servers the **IDE** offers to agents. ChatCLI brings its own MCP client configuration (`~/.chatcli/mcp_servers.json`) either way — tools you configured in ChatCLI keep working inside the IDE.
</Note>

## Zed

Add ChatCLI under `agent_servers` in Zed's `settings.json`:

```json theme={"system"}
{
  "agent_servers": {
    "ChatCLI": {
      "command": "/usr/local/bin/chatcli",
      "args": ["acp"],
      "env": { "LLM_PROVIDER": "CLAUDEAI" }
    }
  }
}
```

Then open the Agent Panel and select **ChatCLI**.

## Session modes

Every ACP session runs in one of three modes, advertised to the client on `session/new` and switchable at any time:

| Mode    | What it is                                                                                                                               | Default |
| ------- | ---------------------------------------------------------------------------------------------------------------------------------------- | ------- |
| `coder` | The full agent loop with every ChatCLI tool: read/edit files, run commands, iterate — with live plan tracking. Recommended for any task. | ✓       |
| `chat`  | Direct model conversation — no tools, full experience pipeline (memory, contexts, skills).                                               |         |
| `agent` | The command-oriented loop that proposes shell commands step by step.                                                                     |         |

Switch modes from the IDE's mode picker, or simply type the command in the prompt:

```
/coder            → switch this session to coder mode
/coder fix the failing tests   → switch AND run the task immediately
/chat             → back to plain conversation
```

Mode changes are confirmed to the client via `current_mode_update`, so the IDE picker always reflects reality.

## Slash commands in the IDE

Type `/` in the prompt box: the IDE autocompletes ChatCLI's command surface (advertised via `available_commands_update`). Each command's **input hint shows its real subcommands** — derived live from the same completer that powers the terminal, so it never drifts (the ACP protocol has no structured completion past the command name; the hint line is the whole surface, and ChatCLI makes it count). Three groups:

**Mode switches** — `/chat`, `/agent`, `/coder` (and `/run` as an alias for agent).

**Slash-command templates** — every command from the project's [slash-command catalog](/features/slash-commands) (`.chatcli/commands`, `~/.chatcli/commands` and every interop dir — Claude Code, Devin, Windsurf, Cursor, opencode, Codex, Gemini, Qwen, Copilot) is advertised with its `argument-hint` as the input hint. Invoking one expands the template and runs it through the session's current mode, exactly like typed text.

**Headless-capable commands** — run for real, output returned to the chat:

| Category         | Commands                                                                                                                                                |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Model & provider | `/switch <provider> [--model <m>]`, `/provider`, `/model`, `/max-tokens`                                                                                |
| Configuration    | `/config` (panorama and every section: `/config providers`, `/config agent`, `/config ui theme <name>`, …)                                              |
| Session          | `/session` (per-session: `save`, `load`, `attach`, `detach`, `status`, `list`, `search`, `delete`, `new`, `fork`), `/newsession`, `/compact`, `/export` |
| Context & memory | `/context`, `/memory`                                                                                                                                   |
| Quality pipeline | `/thinking`, `/refine`, `/verify`, `/reflect`, `/moa`                                                                                                   |
| Integrations     | `/mcp`, `/websearch`, `/skill`, `/plugin`                                                                                                               |
| Security         | `/policy` (session policy mode: `mode auto`, `mode interactive`, `status`)                                                                              |
| Diagnostics      | `/cost`, `/metrics`, `/ratelimit`, `/version`, `/help`                                                                                                  |

**Everything else** — commands that need a live terminal (`/menu`, `/gateway`, `/schedule`, `/auth`, …) answer with a clear "not available over the IDE connection" message instead of failing silently.

`/session` operates **on the caller's session**, not on process-global state: each IDE session saves, loads and binds independently. `/session attach <name>` (or `save`/`load`) binds the IDE conversation to a named session in the shared store — every turn is written through and writes from other surfaces (terminal REPL, gateway, MCP clients) are adopted before each turn. See [Cross-surface continuity](/features/session-management#cross-surface-continuity).

<Note>
  A prompt that merely *starts* with a slash — a filesystem path like `/usr/local/bin explain this`, a typo'd word — is **not** hijacked: unknown tokens flow to the model as normal user text.
</Note>

<Warning>
  Commands that would ask for confirmation on a terminal (e.g. `/context rm <name>`) run with stdin quarantined on the server: any confirmation is answered as **deny, fail-safe**. Destructive maintenance is best done in the terminal REPL.
</Warning>

## Permission dialogs

Unattended agent servers historically face a hard choice: auto-approve everything or block everything. ACP has a better answer — `session/request_permission` — and ChatCLI uses it:

* Your [security policy](/features/coder-security) **`ask` rules** raise the IDE's native dialog with the **full terminal vocabulary**: *Allow* / *Always allow* / *Reject* / *Always reject*. The *always* choices persist a rule in `coder_policy.json` — exactly what pressing `a` or `d` does in the terminal prompt — so the next match never needs a dialog.
* When the coder wants to run a command classified **dangerous** (recursive deletes, force pushes, privilege escalation…), the dialog offers **Allow once** / **Reject once** only: `exec` commands never get a blanket *always*, matching the interactive prompt that hides those options for them on purpose.
* Anything except an explicit *Allow* — reject, dialog dismissed, client crash, timeout — **denies** the action. The agent sees the refusal in-band and replans; an *Always reject* also records a permanent deny rule.
* The same gate covers shell blocks the agent proposes in agent mode.

A dialog that never gets an answer cannot freeze the run: the wait is bounded by **`CHATCLI_MCP_PERMISSION_TIMEOUT`** (shared with the [MCP server](/features/mcp-server#approval-prompts-via-elicitation); a Go duration like `90s`/`10m` or plain seconds, default `600s`; `0`/`off` lifts the bound to a 24h ceiling). On expiry the action **denies fail-safe**, the model is told the request went **unanswered** — not that you denied it — so it can continue and explain, and later dialogs in the same run fail fast instead of stalling again.

Prefer no dialogs at all for a session? `/policy mode auto` switches the session into [policy automode](/features/coder-security#session-policy-mode-policy): `ask` rules auto-approve while deny rules and safety-immune operations keep gating. `/policy mode interactive` restores the dialogs.

Clients that don't implement the permission request (answering *method not found*) keep working without it: dangerous commands are refused fail-safe, while policy `ask` rules fall back to the historical unattended contract (auto-approve) — so minimal or wrapped frontends are never bricked. Explicit `deny` rules block on every surface.

## Your MCP servers work here too

The ACP process is a full ChatCLI boot — including the **MCP client**. If `~/.chatcli/mcp_servers.json` exists, every configured MCP server is connected at startup and its tools join the agent's toolbox, exactly like in the terminal:

* Ask the agent something that needs an MCP tool ("check the open Jira issues", "query the staging database") and it calls the connected server's tool autonomously. In the IDE, the call renders as a **native structured tool call** like any built-in.
* **Hot reload** — editing `mcp_servers.json` reconnects servers live; no IDE or agent restart needed. `/mcp` from the prompt box shows connection status and tools.
* Remote servers using OAuth must be authorized beforehand (run `@mcp-login` in the terminal once; tokens persist in the keychain).

<Note>
  Connections are established asynchronously at boot: a prompt sent in the very first seconds may not see a slow server's tools yet — they join the catalog as soon as the connection completes.

  One conceptual difference from `chatcli mcp-server`: ACP has no client-facing tool list, so the IDE never invokes MCP tools directly — the **agent** uses them on your behalf. Direct tool invocation (hub passthrough) is an MCP-server feature.
</Note>

## Under the hood (for integrators)

ChatCLI implements ACP **protocol version 1**. Methods:

| Method             | Notes                                                                                                                                                                                                                                                                                                                                      |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `initialize`       | Returns `agentInfo {name: "chatcli", version}`, capabilities (`loadSession: true`, `embeddedContext: true`), no auth required.                                                                                                                                                                                                             |
| `session/new`      | Returns `sessionId` + `modes`; `available_commands_update` follows immediately after the response.                                                                                                                                                                                                                                         |
| `session/load`     | Restores a prior `sessionId` — the live in-process state, or the rolling `mcp-<id>` autosave mirror when the server was restarted — and **replays the conversation** as `session/update` chunks (user/agent message chunks) after the response, then re-advertises modes and commands. `cwd`/`mcpServers` params are accepted and ignored. |
| `session/set_mode` | Validates the mode, confirms via `current_mode_update`.                                                                                                                                                                                                                                                                                    |
| `session/prompt`   | Accepts `text`, `resource_link` and embedded `resource` content blocks. One prompt at a time per session — an overlapping prompt is rejected, not queued.                                                                                                                                                                                  |
| `session/cancel`   | Interrupts the in-flight prompt (`stopReason: "cancelled"`); any announced-but-unfinished tool call is closed as `failed`, so no spinner is ever orphaned.                                                                                                                                                                                 |

`session/update` kinds emitted: `agent_thought_chunk`, `agent_message_chunk`, `tool_call`, `tool_call_update`, `plan`, `current_mode_update`, `available_commands_update`. Tool calls carry `kind` (`read`/`edit`/`delete`/`move`/`search`/`execute`/`think`/`fetch`/`other`), `status`, `rawInput`, `locations` (file paths for follow-along), and content capped for display — the model always receives the full output; the chat view gets a bounded summary.

File mentions from the IDE work both ways: `resource_link` blocks arrive as file references the agent's tools open themselves, and `resource` blocks (embedded contents) are injected as attached context.

## Operational notes

* **One run at a time** — agent/coder runs serialize process-wide (they share the engine state). A second session's prompt waits for the current run to finish; a second prompt on the *same* session is rejected while one is in flight — and a queued session that you cancel gives up its place immediately instead of staying wedged behind the active run.
* **Parks and monitors stay in-turn** — when the model uses `@park` (e.g. "check the PR gate every 30s"), the turn stays open and every monitoring cycle streams into the IDE on the same request; pressing Stop cancels the monitor completely (scheduler job + snapshot). Synchronous `@scheduler` waits emit a ⏳ heartbeat line every 30s. See [Agent park & resume](/features/agent-park#parks-on-acp-mcp-server-and-gateway).
* **Permission dialogs are bounded and honest** — each `session/request_permission` waits up to `CHATCLI_MCP_PERMISSION_TIMEOUT` (default 600s; `off` = 24h ceiling). A timeout or a failed dialog round-trip blocks the action fail-safe but is reported to the model as *unanswered/failed*, never as a user denial.
* **Environment** — the ACP process is a normal ChatCLI boot: `.env`, keychain-backed OAuth logins, provider catalogs, MCP client config and skills all resolve exactly as in your terminal.
* **Sessions are per-session and restorable** — each IDE session keeps its own conversation history. `session/load` (capability `loadSession: true`) brings a prior session id back: live state if the server is still running, or the `mcp-<id>` autosave mirror after a restart, with the conversation replayed into the IDE. For durable continuity across surfaces, bind to a named session with `/session attach <name>` — see [Cross-surface continuity](/features/session-management#cross-surface-continuity).
* **Logs** — stdout is the protocol; diagnostics go to the standard ChatCLI log file. Set `LOG_LEVEL=debug` in the agent's `env` block when investigating.

## Troubleshooting

| Symptom                                                   | Fix                                                                                                                                                                             |
| --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Agent doesn't appear in the IDE dropdown                  | Validate `~/.jetbrains/acp.json` syntax; restart the IDE.                                                                                                                       |
| Agent fails to start                                      | Use the **absolute** binary path in `command`; test `chatcli acp` in a terminal — type `{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}` and expect a JSON response. |
| Empty replies in chat mode                                | Provider/model not resolvable in the ACP process environment — set `LLM_PROVIDER`/`LLM_MODEL` (or API keys) in the `env` block.                                                 |
| A command answers "not available over the IDE connection" | It needs a live terminal — run it in the REPL. The `/` autocomplete lists everything that works headless.                                                                       |
| Dangerous command silently refused                        | Your client doesn't implement `session/request_permission`; ChatCLI fails safe. Run it from the terminal, or approve via the dialog in a client that supports it.               |

## See also

* [MCP Server](/features/mcp-server) — the sibling subcommand: ChatCLI's full surface as MCP tools
* [Coder Plugin](/features/coder-plugin) — what the coder engine can do
* [Coder Security](/features/coder-security) — the dangerous-command classification behind permission dialogs
* [Command Reference](/reference/command-reference) — the full slash-command surface
* [Environment Variables](/reference/environment-variables) — provider/model/security knobs
