---
title: "RPC Mode"
source: https://docs.autohand.ai/integrations/rpc-mode
---

# RPC Mode

Control Autohand programmatically via JSON protocol over stdin/stdout. Perfect for building custom UIs, IDE integrations, and automation tools.

Quick answer

## What is the Autohand RPC Mode integration?

Autohand RPC Mode exposes a newline-delimited JSON protocol over stdin and stdout. A parent process can start the CLI, send prompts and control messages, and consume structured events without parsing the interactive terminal interface.

Status

Available

Requires

A local process that can manage Autohand stdin, stdout, lifecycle, and any model-provider credentials.

Configure with

Start Autohand in RPC mode, send one JSON message per line, and keep stdout reserved for protocol events as documented below.

Best for

Custom interfaces, scripts, test harnesses, and process-level automation.

**Know before you start:** The host application owns process supervision, message ordering, secret injection, error handling, and protocol-version compatibility.

## Overview

RPC mode enables headless operation of the Autohand CLI via a JSON-RPC protocol. This allows external applications to:

-   Send prompts and receive streaming responses
-   Monitor tool execution in real-time
-   Handle permission requests programmatically
-   Control auto-mode, plan mode, and YOLO mode
-   Manage skills and MCP servers
-   Build custom UIs and IDE extensions
-   Create automated pipelines with full agent control

**Looking for session-managed connections?** If you need persistent sessions, model switching, and editor-style integration, see [ACP Mode](/docs/integrations/acp-mode.html) instead.

## Getting Started

### Start RPC Mode

Launch Autohand in RPC mode:

``` bash
# Basic RPC mode
autohand --mode rpc

# With options
autohand --mode rpc --model nvidia/nemotron-3-super-120b-a12b:free --ephemeral

# All options
autohand --mode rpc \
  --model <model-id> \
  --ephemeral \
  --thinking <level> \
  --config <path>
```

### Protocol Basics

The protocol uses newline-delimited JSON (JSON Lines):

-   **Commands**: JSON objects sent to stdin, one per line
-   **Responses**: JSON objects with `type: "response"`
-   **Events**: JSON objects streamed during agent operation

**Correlation IDs:** Include an optional `id` field in commands. The corresponding response will include the same `id` for matching.

## Core Commands

### prompt

Send an instruction to the agent:

``` json
{"type": "prompt", "message": "Create a hello.ts file", "id": "1"}

// With file context
{"type": "prompt", "message": "Review this file", "mentions": ["src/index.ts"]}
```

### abort

Cancel the current operation:

``` json
{"type": "abort"}
```

### reset

Clear conversation context:

``` json
{"type": "reset"}
```

### get\_state

Get current agent state:

``` json
{"type": "get_state"}

// Response
{
  "type": "response",
  "command": "get_state",
  "success": true,
  "data": {
    "model": "nvidia/nemotron-3-super-120b-a12b:free",
    "provider": "openrouter",
    "workspace": "/path/to/project",
    "isProcessing": false,
    "contextPercent": 85,
    "messageCount": 5
  }
}
```

### get\_messages

Get conversation history:

``` json
{"type": "get_messages"}
```

### get\_history

Get the full session history including tool calls and results:

``` json
{"type": "get_history"}

// Response
{
  "type": "response",
  "command": "get_history",
  "success": true,
  "data": {
    "messages": [...],
    "toolCalls": [...],
    "totalTokens": 12500
  }
}
```

### permission\_response

Respond to a permission request:

``` json
{"type": "permission_response", "requestId": "perm-123", "approve": true}
```

## Auto-Mode Commands

Control the autonomous execution mode programmatically. Auto-mode lets the agent work through tasks without requiring manual prompt-by-prompt interaction.

### automode\_start

Start auto-mode with an initial instruction:

``` json
{"type": "automode_start", "message": "Refactor the auth module", "id": "am-1"}

// Response
{
  "type": "response",
  "command": "automode_start",
  "success": true,
  "data": {"status": "running"}
}
```

### automode\_status

Check the current auto-mode status:

``` json
{"type": "automode_status"}

// Response
{
  "type": "response",
  "command": "automode_status",
  "success": true,
  "data": {
    "active": true,
    "paused": false,
    "turnsCompleted": 3,
    "turnsRemaining": 7
  }
}
```

### automode\_pause

Pause a running auto-mode session:

``` json
{"type": "automode_pause"}
```

### automode\_resume

Resume a paused auto-mode session:

``` json
{"type": "automode_resume"}
```

### automode\_cancel

Cancel auto-mode entirely:

``` json
{"type": "automode_cancel"}
```

### automode\_get\_log

Get the auto-mode execution log:

``` json
{"type": "automode_get_log"}

// Response
{
  "type": "response",
  "command": "automode_get_log",
  "success": true,
  "data": {
    "entries": [
      {"turn": 1, "action": "Read file src/auth.ts", "timestamp": "..."},
      {"turn": 2, "action": "Edited src/auth.ts", "timestamp": "..."}
    ]
  }
}
```

## Skill Commands

Manage the agent's skill registry programmatically.

### get\_skills\_registry

List all available skills:

``` json
{"type": "get_skills_registry"}

// Response
{
  "type": "response",
  "command": "get_skills_registry",
  "success": true,
  "data": {
    "skills": [
      {
        "name": "commit",
        "description": "Create a git commit",
        "source": "builtin"
      },
      {
        "name": "review-pr",
        "description": "Review a pull request",
        "source": "plugin:code-review"
      }
    ]
  }
}
```

### install\_skill

Install a skill from a registry or path:

``` json
{
  "type": "install_skill",
  "source": "npm:@autohand/skill-tdd",
  "id": "sk-1"
}

// Response
{
  "type": "response",
  "command": "install_skill",
  "success": true,
  "data": {"name": "tdd", "installed": true}
}
```

## MCP Commands

Manage Model Context Protocol servers and tools.

### mcp\_list\_servers

List configured MCP servers:

``` json
{"type": "mcp_list_servers"}

// Response
{
  "type": "response",
  "command": "mcp_list_servers",
  "success": true,
  "data": {
    "servers": [
      {"name": "context7", "status": "connected", "tools": 2},
      {"name": "brave-search", "status": "connected", "tools": 1}
    ]
  }
}
```

### mcp\_list\_tools

List all available MCP tools across servers:

``` json
{"type": "mcp_list_tools"}

// Response
{
  "type": "response",
  "command": "mcp_list_tools",
  "success": true,
  "data": {
    "tools": [
      {"name": "query-docs", "server": "context7"},
      {"name": "brave_web_search", "server": "brave-search"}
    ]
  }
}
```

### mcp\_get\_server\_configs

Get the full configuration for all MCP servers:

``` json
{"type": "mcp_get_server_configs"}

// Response
{
  "type": "response",
  "command": "mcp_get_server_configs",
  "success": true,
  "data": {
    "configs": {
      "context7": {
        "command": "npx",
        "args": ["-y", "@upstash/context7-mcp@latest"]
      }
    }
  }
}
```

### mcp\_set\_vscode\_tools

Configure MCP tools for VS Code integration. This syncs tool availability between the CLI and VS Code extension:

``` json
{
  "type": "mcp_set_vscode_tools",
  "tools": ["query-docs", "brave_web_search"]
}
```

### mcp\_invoke\_response

Send the result of an MCP tool invocation back to the agent. Used when the host application handles tool execution:

``` json
{
  "type": "mcp_invoke_response",
  "toolCallId": "call_abc123",
  "result": {"content": "Search results..."}
}
```

## Mode Commands

Control agent operation modes.

### plan\_mode\_set

Toggle plan mode on or off. In plan mode, the agent designs an approach before making changes:

``` json
// Enable plan mode
{"type": "plan_mode_set", "enabled": true}

// Disable plan mode
{"type": "plan_mode_set", "enabled": false}

// Response
{
  "type": "response",
  "command": "plan_mode_set",
  "success": true,
  "data": {"planMode": true}
}
```

### yolo\_set

Toggle YOLO mode. When enabled, the agent auto-approves all tool executions without permission prompts:

``` json
// Enable YOLO mode
{"type": "yolo_set", "enabled": true}

// With specific patterns
{"type": "yolo_set", "enabled": true, "patterns": ["npm *", "git *"]}

// Response
{
  "type": "response",
  "command": "yolo_set",
  "success": true,
  "data": {"yolo": true}
}
```

**Use YOLO mode with care:** Auto-approving all operations can lead to unwanted changes. Consider using patterns to limit which commands are auto-approved.

## File Change Commands

### changes\_decision

Accept or reject file changes proposed by the agent. When the agent writes or edits files, you can review and decide on each change:

``` json
// Accept changes
{
  "type": "changes_decision",
  "changeId": "chg-456",
  "decision": "accept"
}

// Reject changes
{
  "type": "changes_decision",
  "changeId": "chg-456",
  "decision": "reject"
}

// Response
{
  "type": "response",
  "command": "changes_decision",
  "success": true,
  "data": {"applied": true}
}
```

## Events

Events are streamed to stdout during agent operation:

| Event | Description |
|---|---|
| agent_start | Agent ready to accept commands |
| agent_end | Agent shutting down |
| turn_start | Started processing a prompt |
| turn_end | Finished processing a prompt |
| message_start | LLM response started |
| message_update | Streaming content delta |
| message_end | LLM response completed |
| tool_execution_start | Tool execution started |
| tool_execution_update | Tool output chunk |
| tool_execution_end | Tool execution completed |
| permission_request | Awaiting approval for action |
| automode_turn | Auto-mode completed a turn |
| automode_complete | Auto-mode finished all turns |
| file_change | File was created, modified, or deleted |
| error | Error occurred |

### Event Examples

``` json
// Turn lifecycle
{"type": "turn_start", "timestamp": "...", "data": {"instruction": "Create a file"}}
{"type": "turn_end", "timestamp": "...", "data": {"success": true}}

// Message streaming
{"type": "message_update", "timestamp": "...", "data": {"delta": "I'll create "}}

// Tool execution
{"type": "tool_execution_start", "timestamp": "...", "data": {
  "toolName": "write_file",
  "toolCallId": "call_abc",
  "args": {"path": "hello.ts"}
}}
{"type": "tool_execution_end", "timestamp": "...", "data": {
  "toolName": "write_file",
  "toolCallId": "call_abc",
  "success": true,
  "duration": 150
}}

// Permission request
{"type": "permission_request", "timestamp": "...", "data": {
  "requestId": "perm-123",
  "tool": "run_command",
  "message": "Execute: npm install?"
}}

// Auto-mode events
{"type": "automode_turn", "timestamp": "...", "data": {
  "turn": 3,
  "total": 10,
  "action": "Edited src/auth.ts"
}}
{"type": "automode_complete", "timestamp": "...", "data": {
  "turnsCompleted": 5,
  "success": true
}}

// File change
{"type": "file_change", "timestamp": "...", "data": {
  "path": "src/hello.ts",
  "action": "created",
  "changeId": "chg-456"
}}
```

## Examples

### Python Client

``` python
import subprocess
import json

proc = subprocess.Popen(
    ["autohand", "--mode", "rpc", "--ephemeral"],
    stdin=subprocess.PIPE,
    stdout=subprocess.PIPE,
    text=True
)

def send(cmd):
    proc.stdin.write(json.dumps(cmd) + "\n")
    proc.stdin.flush()

def read_events():
    for line in proc.stdout:
        yield json.loads(line)

# Wait for ready
for event in read_events():
    if event.get("type") == "agent_start":
        break

# Send prompt
send({"type": "prompt", "message": "Hello!", "id": "1"})

# Process events
for event in read_events():
    if event.get("type") == "message_update":
        print(event["data"]["delta"], end="", flush=True)

    if event.get("type") == "permission_request":
        # Handle permission
        send({
            "type": "permission_response",
            "requestId": event["data"]["requestId"],
            "approve": True
        })

    if event.get("type") == "turn_end":
        print()
        break

proc.terminate()
```

### Node.js Client

``` javascript
const { spawn } = require("child_process");
const readline = require("readline");

const agent = spawn("autohand", ["--mode", "rpc", "--ephemeral"]);

const rl = readline.createInterface({ input: agent.stdout });

rl.on("line", (line) => {
    const event = JSON.parse(line);

    if (event.type === "message_update") {
        process.stdout.write(event.data.delta);
    }

    if (event.type === "permission_request") {
        agent.stdin.write(JSON.stringify({
            type: "permission_response",
            requestId: event.data.requestId,
            approve: true
        }) + "\n");
    }

    if (event.type === "turn_end") {
        console.log("\n--- Done ---");
    }
});

// Send prompt after ready
setTimeout(() => {
    agent.stdin.write(JSON.stringify({
        type: "prompt",
        message: "List files in current directory"
    }) + "\n");
}, 1000);

process.on("SIGINT", () => {
    agent.stdin.write(JSON.stringify({ type: "abort" }) + "\n");
    agent.kill();
});
```

### Auto-Mode Example

``` python
import subprocess
import json

proc = subprocess.Popen(
    ["autohand", "--mode", "rpc"],
    stdin=subprocess.PIPE,
    stdout=subprocess.PIPE,
    text=True
)

def send(cmd):
    proc.stdin.write(json.dumps(cmd) + "\n")
    proc.stdin.flush()

def read_events():
    for line in proc.stdout:
        yield json.loads(line)

# Wait for ready
for event in read_events():
    if event.get("type") == "agent_start":
        break

# Enable YOLO mode for auto-approval
send({"type": "yolo_set", "enabled": True, "patterns": ["git *"]})

# Start auto-mode
send({
    "type": "automode_start",
    "message": "Add unit tests for the auth module"
})

# Monitor progress
for event in read_events():
    if event.get("type") == "automode_turn":
        d = event["data"]
        print(f"Turn {d['turn']}/{d['total']}: {d['action']}")

    if event.get("type") == "automode_complete":
        print("Auto-mode finished!")
        break

proc.terminate()
```

## Use Cases

### IDE Extensions

Build VS Code, JetBrains, or Zed extensions that embed Autohand:

-   Spawn RPC process on extension activation
-   Send file context with `mentions`
-   Display streaming responses in editor panels
-   Handle permission requests via UI dialogs

### Custom Web UIs

Create browser-based interfaces:

-   Backend spawns RPC process
-   WebSocket bridges JSON events to browser
-   React/Vue components render streaming output
-   Users approve/deny via web interface

### CI/CD Integration

Programmatic control in pipelines:

-   Auto-approve safe operations with YOLO patterns
-   Use auto-mode for multi-step tasks
-   Collect structured output for reports
-   Chain multiple prompts in sequence

## Error Handling

Failed commands return responses with `success: false`:

``` json
{
  "type": "response",
  "command": "prompt",
  "success": false,
  "error": "Agent is already processing a request"
}

// Parse errors
{
  "type": "response",
  "command": "parse",
  "success": false,
  "error": "Invalid JSON: Unexpected token..."
}
```

**Always handle errors:** Check `success` field in responses and listen for `error` events to handle failures gracefully.

## Future Commands

These commands are planned for future releases:

-   **Model**: `set_model`, `cycle_model`, `get_available_models`
-   **Thinking**: `set_thinking_level`, `cycle_thinking_level`
-   **Compaction**: `compact`, `set_auto_compaction`

Common questions

## RPC Mode integration FAQ

### How do I configure the Autohand RPC Mode integration?

Start Autohand in RPC mode, send one JSON message per line, and keep stdout reserved for protocol events as documented below.

### What does the Autohand RPC Mode integration require?

A local process that can manage Autohand stdin, stdout, lifecycle, and any model-provider credentials.

### What limitations should I know about?

The host application owns process supervision, message ordering, secret injection, error handling, and protocol-version compatibility.