Python Sidecar IPC Reference
JSON-RPC protocol specification for communication between the Rust host (dspy_daemon.rs) and the Python sidecar
(apps/python-sidecar/).
Transport
The sidecar communicates via stdin/stdout, one JSON object per line (newline-delimited JSON). The Rust host writes requests to the sidecar’s stdin and reads responses from its stdout. Stderr is reserved for logging and DSPy’s internal print output.
Request Format
{ "type": "<request_type>", "params": { ... }}All requests have a type field and an optional params object.
Response Format
Success
{ "type": "response", "status": "ok", "result": { ... }}Error
{ "type": "response", "status": "error", "error_code": "<machine_readable_code>", "message": "<human_readable_description>", "details": { ... }}The details field is optional and provides additional context (e.g., available templates when a template is not
found).
Request Types
health_check
Verify the sidecar is running and report version/configuration status.
Request:
{ "type": "health_check" }Response:
{ "type": "response", "status": "ok", "result": { "healthy": true, "dspy_available": true, "sidecar_version": "0.1.0", "dspy_version": "2.6.1", "llm_configured": false }}configure
Configure the LLM connection. Must be called before execute or optimize.
Request:
{ "type": "configure", "params": { "model": "anthropic/claude-sonnet-4-20250514", "credentials": { "api_key": "sk-..." } }}Response:
{ "type": "response", "status": "ok", "result": { "configured": true }}Note: In production, LLM calls are routed through the InklingsLM adapter back to Rust via IPC. The credentials
field is used only for direct LLM access during development/testing.
execute
Run a template with inputs and optional saved state.
Request:
{ "type": "execute", "params": { "template_id": "chain_of_thought", "signature": "question -> answer", "params": { "question": "What is the capital of France?" }, "state_blob": null }}| Field | Type | Required | Description |
|---|---|---|---|
template_id | string | yes | ID from the template registry |
signature | string | no | DSPy signature (overrides template default) |
params | object | no | Input fields matching the signature |
state_blob | object/null | no | Previously saved state to restore before execution |
Success Response:
{ "type": "response", "status": "ok", "result": { "answer": "Paris" }, "state_blob": { "...": "serialized DSPy module state" }}The state_blob in the response contains the module’s state after execution. Store it to restore the same state in
future calls.
Error Responses:
| Error Code | Condition |
|---|---|
llm_not_configured | No configure message received yet |
missing_field | template_id not provided |
unknown_template | template_id not in registry (includes available list in details) |
invalid_state | state_blob could not be deserialized |
execution_failed | Template forward() raised an exception |
optimize
Run a DSPy optimizer on a template to produce an improved state blob.
Request:
{ "type": "optimize", "params": { "template_id": "predict", "optimizer": "BootstrapFewShot", "signature": "input -> output", "examples": [ { "input": "hello", "output": "world" } ] }}| Field | Type | Required | Description |
|---|---|---|---|
template_id | string | yes | Template to optimize |
optimizer | string | yes | DSPy optimizer class name (must be in allowlist) |
signature | string | no | DSPy signature |
examples | array | yes | Training examples for the optimizer |
Allowed optimizers: BootstrapFewShot, BootstrapFewShotWithRandomSearch, LabeledFewShot, COPRO, MIPRO,
MIPROv2, SignatureOptimizer, BayesianSignatureOptimizer, BootstrapFinetune, KNNFewShot
Error Responses:
| Error Code | Condition |
|---|---|
unsupported_optimizer | Optimizer name not in allowlist |
optimizer_not_found | Optimizer class not found in DSPy |
execution_failed | Optimizer raised an exception |
manifest
List all available templates with their metadata.
Request:
{ "type": "manifest" }Response:
{ "type": "response", "status": "ok", "result": { "templates": { "predict": { "description": "Basic DSPy Predict -- single LLM call with signature", "signature": "input -> output", "parameters": {} }, "chain_of_thought": { "description": "Chain of Thought -- step-by-step reasoning before output", "signature": "input -> output", "parameters": {} } } }}Error Codes Reference
| Code | Description |
|---|---|
unknown_template | Template ID not found in registry |
missing_field | Required field not present in request |
invalid_state | State blob deserialization failed |
unsupported_optimizer | Optimizer not in the allowed set |
optimizer_not_found | Optimizer class not available in DSPy |
execution_failed | Runtime error during template execution |
unknown_request_type | Unrecognized request type field |
sandbox_required | Template requires sandbox execution (not available) |
llm_not_configured | LLM not configured — send configure first |
Lifecycle
- Rust spawns the sidecar process with
kill_on_drop(true)and sanitized environment - Rust sends
configurewith LLM credentials (or InklingsLM IPC mode) - Rust sends
health_checkto verify readiness - Rust sends
execute/optimize/manifestas needed - Sidecar auto-shuts down after
DEFAULT_IDLE_TIMEOUT(5 minutes) of inactivity RESPONSE_TIMEOUT(60 seconds) bounds wall-clock time per request
Key Files
| File | Role |
|---|---|
crates/infrastructure/agent-harness/src/dspy_daemon.rs | Rust-side daemon management and IPC |
apps/python-sidecar/main.py | Python-side async stdin/stdout loop |
apps/python-sidecar/src/inklings/dspy/dispatcher.py | Request routing |
apps/python-sidecar/src/inklings/dspy/errors.py | Error codes and structured error responses |
See Also
- Python Sidecar Security — threat model and defense layers
- Skill System — how the harness uses the IPC protocol
- Adding a DSPy Template — template authoring guide
Was this page helpful?
Thanks for your feedback!