PiG Documentation

Guides and references for configuring, using, and extending PiG.

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-session disables 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
promptmessageAccept a prompt, queue it with streamingBehavior, or run a registered extension command.
steermessageQueue a steering message in the active turn.
follow_upmessageQueue a message after the active turn settles.
abortnoneCancel the current prompt and wait for it to settle.
new_sessionnoneReplace the active Session with a fresh Session.
get_commandsnoneList extension, prompt-template, and Skill commands.
get_statenoneRead current Session, queue, and model state.
set_modelprovider, modelIdSelect an available model.
cycle_modelnoneSelect the next available or scoped model.
get_available_modelsnoneList available full model records.
set_thinking_levellevelSet the effective thinking level.
cycle_thinking_levelnoneSelect the next supported level.
get_available_thinking_levelsnoneList levels supported by the current model.
set_steering_modemodeSet and persist all or one-at-a-time.
set_follow_up_modemodeSet and persist all or one-at-a-time.
compactnoneRun manual compaction and return its result.
set_auto_compactionenabledPersist automatic-compaction state.
set_auto_retryenabledSet automatic retry for this Session.
abort_retrynoneCancel the active retry delay.
bashcommandRun a shell command and stream output records.
abort_bashnoneCancel active RPC Bash commands.
get_session_statsnoneRead Session statistics.
export_htmlnoneExport the Session to HTML.
switch_sessionsessionPathReplace the active Session from a file.
forkentryIdFork before a user message and return its text.
clonenoneClone at the active leaf and switch to the clone.
get_fork_messagesnoneList user messages that can identify a fork point.
get_entriesoptional sinceRead Session entries after an entry ID.
get_treenoneRead the Session entry tree and active leaf.
get_last_assistant_textnoneRead the last assistant text, when present.
set_session_namenameSet the current Session name.
get_messagesnoneRead 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 as extension, prompt, or skill;
  • sourceInfo with path, source, scope, origin, and optional baseDir.

Built-in interactive slash commands are not RPC commands.

Events

PiG currently emits these model-loop events:

  • agent_start;
  • agent_end with messages and willRetry;
  • agent_settled;
  • turn_start;
  • turn_end with 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_start and compaction_end;
  • automatic-retry and summarization-retry events;
  • entry_appended after 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.go defines the command loop.
  • cmd/pig/rpc_types.go defines command and response types.
  • cmd/pig/rpc_ui.go defines the extension UI request and response transport.
  • cmd/pig/rpc_events.go defines event conversion.
  • coding/rpcclient defines the Go subprocess client.

Upstream Pi reference:

Adapted from upstream Pi documentation · Upstream documentation ↗ · MIT License