RPC mode
RPC mode runs PiG as a headless JSON Lines process. A client writes commands to standard input and reads responses and events from standard output.
Use the PiG Go SDK when your Go application does not need a process boundary. Use RPC mode for another language, an IDE, or a separate process.
Start RPC mode
pig --mode rpc [--model <provider/model>] [options]Common options:
--provider <name>selects a provider when the model argument does not include one.--model <provider/model>selects the model.--name <name>or-n <name>sets the initial Session name.--no-sessiondisables Session persistence.--session-dir <path>selects a Session directory.--piglet <name-or-path>selects one agent application.
PiG writes operational diagnostics to standard error. Treat standard output as protocol data only.
If you omit --model and no default model exists, RPC mode starts with Pi's
unknown model record. Use get_state, get_available_models, and set_model
to select a model. A prompt fails preflight until the selected provider has
configured authentication.
Framing
Each input or output record is one JSON object followed by LF (\n).
- Split records on LF only.
- Remove a trailing CR when you send CRLF.
- Do not split JSON strings on Unicode line separators.
- Keep each input command within the 16 MiB command-reader limit.
Every command can contain an id. The corresponding response repeats it:
{"id":"req-1","type":"get_state"}{"id":"req-1","type":"response","command":"get_state","success":true,"data":{}}A response confirms command acceptance or reports a command error. Later model or tool failures arrive as events.
Supported commands
Command | Required fields | Purpose |
prompt | message | Accept a prompt, queue it with streamingBehavior, or run a registered extension command. |
steer | message | Queue a steering message in the active turn. |
follow_up | message | Queue a message after the active turn settles. |
abort | none | Cancel the current prompt and wait for it to settle. |
new_session | none | Replace the active Session with a fresh Session. |
get_commands | none | List extension, prompt-template, and Skill commands. |
get_state | none | Read current Session, queue, and model state. |
set_model | provider, modelId | Select an available model. |
cycle_model | none | Select the next available or scoped model. |
get_available_models | none | List available full model records. |
set_thinking_level | level | Set the effective thinking level. |
cycle_thinking_level | none | Select the next supported level. |
get_available_thinking_levels | none | List levels supported by the current model. |
set_steering_mode | mode | Set and persist all or one-at-a-time. |
set_follow_up_mode | mode | Set and persist all or one-at-a-time. |
compact | none | Run manual compaction and return its result. |
set_auto_compaction | enabled | Persist automatic-compaction state. |
set_auto_retry | enabled | Set automatic retry for this Session. |
abort_retry | none | Cancel the active retry delay. |
bash | command | Run a shell command and stream output records. |
abort_bash | none | Cancel active RPC Bash commands. |
get_session_stats | none | Read Session statistics. |
export_html | none | Export the Session to HTML. |
switch_session | sessionPath | Replace the active Session from a file. |
fork | entryId | Fork before a user message and return its text. |
clone | none | Clone at the active leaf and switch to the clone. |
get_fork_messages | none | List user messages that can identify a fork point. |
get_entries | optional since | Read Session entries after an entry ID. |
get_tree | none | Read the Session entry tree and active leaf. |
get_last_assistant_text | none | Read the last assistant text, when present. |
set_session_name | name | Set the current Session name. |
get_messages | none | Read current Agent messages. |
Unknown command types return success:false.
Pi compatibility boundary
PiG implements the command union in the pinned Pi rpc-types.ts. The generated
test inventory fails when a pinned Pi command has no PiG dispatch branch.
Close standard input to shut down RPC mode. PiG cancels active prompts, Bash commands, Session transitions, model-selection handlers, retries, and extension UI requests before it closes the process.
Go programs can use github.com/MichaelKinsy/PiG/coding/rpcclient, the port of
Pi's TypeScript RpcClient. It starts pig --mode rpc, correlates responses,
exposes typed command methods, and delivers events to listeners. Other
languages use the JSONL protocol directly.
PiG reuses its host-scoped extension runner when it replaces a Session. Pi invalidates the old per-Session runner. This difference is D30. Session lifecycle events still run before and after each replacement.
Prompt
{"id":"prompt-1","type":"prompt","message":"Find the test entry points"}PiG acknowledges the prompt after extension input handling and model authentication preflight succeed. The response arrives before model events finish:
{"id":"prompt-1","type":"response","command":"prompt","success":true}metadata is an optional JSON object:
{"id":"prompt-2","type":"prompt","message":"Review this change","metadata":{"task_id":"task-42"}}RPC prompt input accepts text and optional images. If the Agent is already
running, set streamingBehavior to steer or followUp. PiG rejects a second
prompt without this field.
A registered extension command such as /review strict runs immediately through the prompt command. Prompt templates and /skill:<name> expand before model submission.
Abort
{"id":"abort-1","type":"abort"}PiG cancels the current prompt context and acknowledges the command:
{"id":"abort-1","type":"response","command":"abort","success":true}State
{"id":"state-1","type":"get_state"}The response data contains:
{
"sessionId":"...",
"sessionFile":"...",
"sessionName":"...",
"model":{"id":"gpt-5","provider":"openai"},
"thinkingLevel":"medium",
"steeringMode":"all",
"followUpMode":"one-at-a-time",
"isStreaming":false,
"isCompacting":false,
"autoCompactionEnabled":true,
"messageCount":5,
"pendingMessageCount":0
}sessionFile and sessionName can be absent.
Select a model
{"id":"model-1","type":"set_model","provider":"openai","modelId":"gpt-5"}A successful response contains the full selected model record.
List available models:
{"id":"models-1","type":"get_available_models"}The result is a models array of full Pi model records.
Thinking level
{"type":"set_thinking_level","level":"high"}Accepted values are off, minimal, low, medium, high, xhigh, and max. Model capabilities can clamp the effective level.
Cycle the configured level:
{"type":"cycle_thinking_level"}The response contains the next level.
Compaction and retry
Start compaction:
{"id":"compact-1","type":"compact","customInstructions":"Keep file names and unresolved errors."}The response arrives after compaction finishes. It contains summary,
firstKeptEntryId, tokensBefore, and estimatedTokensAfter. It can also
contain usage and details. A compaction failure returns success:false.
Set automatic compaction:
{"type":"set_auto_compaction","enabled":true}Set automatic retry for the current Session:
{"type":"set_auto_retry","enabled":true}Steer and follow up
{"type":"steer","message":"Stop and inspect the parser first."}PiG queues this message after the current tool batch and before the next model call.
{"type":"follow_up","message":"Then update the documentation."}PiG queues this message after the active turn settles. queue_update events
report both queues when a message enters or leaves them.
Bash
{"id":"bash-1","type":"bash","command":"go test ./...","excludeFromContext":false}The final response data contains output, exitCode, cancelled, truncated,
and optional fullOutputPath.
Cancel active Bash work:
{"type":"abort_bash"}Session data
Get current Agent messages:
{"type":"get_messages"}Get entries after a known entry:
{"type":"get_entries","since":"a1b2c3d4"}The response contains entries and leafId. An unknown since ID returns an error.
Get the complete tree:
{"type":"get_tree"}Get the last assistant text:
{"type":"get_last_assistant_text"}The response data is empty when no assistant text exists.
Set a Session name:
{"id":"name-1","type":"set_session_name","name":"Review authentication"}PiG writes session_info_changed before the success response.
An extension can also change Session metadata. appendEntry persists a custom
entry and then writes entry_appended. setSessionName writes
session_info_changed. An empty extension-defined name clears the Session name,
and the event omits name.
Session replacement and export
Start a new Session:
{"type":"new_session","parentSession":"/optional/parent.jsonl"}Switch to an existing Session:
{"type":"switch_session","sessionPath":"/path/to/session.jsonl"}PiG keeps the startup project Resources when the target Session uses a different working directory. Direct RPC Bash uses the target working directory. Built-in tools, project settings, context files, prompts, skills, themes, and the system prompt still use the startup project. See D61.
Fork before a user message:
{"type":"fork","entryId":"a1b2c3d4"}The fork response contains the selected user text. clone forks at the active
leaf instead:
{"type":"clone"}Each replacement can return data.cancelled:true when an extension cancels its
session_before_switch or session_before_fork event.
Export the current persisted Session:
{"type":"export_html","outputPath":"/tmp/session.html"}Omit outputPath to use the default export path.
Extension UI records
RPC mode binds a functional extension UI transport. A dialog emits an
extension_ui_request record and waits for the matching
extension_ui_response.
Example selector request:
{"type":"extension_ui_request","id":"...","method":"select","title":"Choose","options":["A","B"]}Return a value, confirmation, or cancellation:
{"type":"extension_ui_response","id":"...","value":"A"}{"type":"extension_ui_response","id":"...","confirmed":true}{"type":"extension_ui_response","id":"...","cancelled":true}PiG supports select, confirm, input, and editor as blocking dialogs.
It emits fire-and-forget requests for notify, setStatus, setWidget,
setTitle, and set_editor_text. TUI-only component factories remain no-ops
in RPC mode.
Command catalogue
{"type":"get_commands"}Each result contains:
name;- optional
description; source, such asextension,prompt, orskill;sourceInfowithpath,source,scope,origin, and optionalbaseDir.
Built-in interactive slash commands are not RPC commands.
Events
PiG currently emits these model-loop events:
agent_start;agent_endwithmessagesandwillRetry;agent_settled;turn_start;turn_endwith the assistant message and tool results;message_start;message_update;message_end;tool_execution_start;tool_execution_update;tool_execution_end;bash_execution_update;queue_update;thinking_level_changed;compaction_startandcompaction_end;- automatic-retry and summarization-retry events;
entry_appendedafter an extension persists a custom Session entry;session_info_changed;extension_ui_request;extension_error;error.
message_update contains an assistantMessageEvent. Text and tool-call streams use matching start, delta, and end records. Deltas do not contain cumulative partial messages.
Example text stream:
{"type":"message_start","message":{"role":"assistant","content":[]}}
{"type":"message_update","assistantMessageEvent":{"type":"text_start","contentIndex":0}}
{"type":"message_update","assistantMessageEvent":{"type":"text_delta","contentIndex":0,"delta":"Hello"}}
{"type":"message_update","assistantMessageEvent":{"type":"text_end","contentIndex":0,"content":"Hello"}}
{"type":"message_end","message":{"role":"assistant","content":[{"type":"text","text":"Hello"}]}}Read message and Session entry shapes in Session file format.
Minimal client
import json
import subprocess
process = subprocess.Popen(
["pig", "--mode", "rpc", "--model", "openai/gpt-5", "--no-session"],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
bufsize=1,
)
process.stdin.write(json.dumps({
"id": "prompt-1",
"type": "prompt",
"message": "List the packages in this repository.",
}) + "\n")
process.stdin.flush()
for line in process.stdout:
event = json.loads(line)
print(event)
if event.get("type") == "agent_settled":
break
process.stdin.close()Keep reading standard error separately. A full error pipe can block a child process.
Source references
PiG implementation:
cmd/pig/rpc_mode.godefines the command loop.cmd/pig/rpc_types.godefines command and response types.cmd/pig/rpc_ui.godefines the extension UI request and response transport.cmd/pig/rpc_events.godefines event conversion.coding/rpcclientdefines the Go subprocess client.
Upstream Pi reference: