---
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.

## 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`