IPC Protocol Specification
Complete specification of voria's NDJSON-based inter-process communication protocol.
Protocol Overview
voria uses NDJSON (Newline-Delimited JSON) for communication between Rust CLI and Python engine.
Format Rules (MANDATORY)
- ▶One JSON object per line - no line wrapping
- ▶Newline terminator - exactly after each JSON objectterminal
\n - ▶No multi-line JSON - protocol messages must fit on single line
- ▶Flush after write - must call immediately after writingterminal
flush() - ▶Line-by-line reading - read one complete line at a time
Example
terminal{"command":"plan","issue_id":1}\n {"status":"success","action":"stop","message":"Done"}\n
NOT acceptable:
terminal{"command":"plan", "issue_id":1}
Stdout/Stderr Discipline
Python Side
stdout (ONLY protocol messages):
pythonresponse = {"status": "success", "action": "stop", "message": "Done"} print(json.dumps(response)) # Automatic \n added sys.stdout.flush() # CRITICAL!
stderr (logs and debug info):
pythonlogger.info("Processing issue...") # Goes to stderr logger.debug("Token count: 1000") # Goes to stderr print(f"Debug: {value}", file=sys.stderr) # Goes to stderr
Rust Side
Reads: Only from stdout (line-by-line JSON parsing) Pipes: stderr directly to user console
Message Types
Request (Rust → Python)
Sent by Rust CLI to invoke Python processing.
json{ "command": "plan|issue|apply|graph|test_results", "issue_id": 123, "repo_path": "/path/to/repo", "iteration": 1, "extra_field": "optional" }
Fields:
- ▶(required): The action to performterminal
command - ▶(optional): GitHub issue numberterminal
issue_id - ▶(optional): Local repository pathterminal
repo_path - ▶(optional): Loop iteration count (1-5)terminal
iteration
Command Types:
- ▶: Analyze issue without code changesterminal
plan - ▶: Start full agent loopterminal
issue - ▶: Execute a previously generated planterminal
apply - ▶: Generate dependency graphterminal
graph - ▶: Callback with test resultsterminal
test_results
Response (Python → Rust)
Sent by Python engine to Rust CLI after processing.
json{ "status": "success|pending|error", "action": "apply_patch|run_tests|continue|stop", "message": "Human-readable status message", "patch": "... unified diff format ...", "logs": "... multi-line debug output ...", "token_usage": { "used": 1000, "max": 4000, "cost": 0.05 } }
Fields:
- ▶(required): Success, pending work, or errorterminal
status - ▶(required): What Rust should do nextterminal
action - ▶(required): Human-readable messageterminal
message - ▶(optional): Unified diff format patchterminal
patch - ▶(optional): Multi-line debug logsterminal
logs - ▶(optional): LLM token accountingterminal
token_usage
Status Values:
- ▶: Action completed successfullyterminal
success - ▶: Action in progress, expect more messagesterminal
pending - ▶: Action failed with errorterminal
error
Action Values:
- ▶: Apply the patch to filesystemterminal
apply_patch - ▶: Execute test suiteterminal
run_tests - ▶: Continue to next iterationterminal
continue - ▶: Stop processing, issue is doneterminal
stop
Callback (Rust → Python)
Sent by Rust to inform Python of execution results.
json{ "command": "test_results", "test_status": "passed|failed", "test_logs": "... test output ...", "error": "... error message if failed ..." }
Fields:
- ▶(required):terminal
commandterminaltest_results - ▶(required): passed or failedterminal
test_status - ▶(optional): Test suite outputterminal
test_logs - ▶(optional): Error message if failedterminal
error
Protocol Flow Examples
Example 1: Simple Plan Request
terminalRUST → PYTHON: {"command":"plan","issue_id":1,"iteration":1} PYTHON → RUST: {"status":"success","action":"stop","message":"Plan generated for issue #1"}
Example 2: Full Agent Loop
terminalRUST → PYTHON: {"command":"issue","issue_id":123,"repo_path":"/home/user/repo"} PYTHON → RUST: {"status":"pending","action":"apply_patch","message":"Generated patch","patch":"--- a/src/main.py\n+++ b/src/main.py\n@@ -1,3 +1,3 @@\n..."} RUST applies patch, runs tests RUST → PYTHON: {"command":"test_results","test_status":"failed","test_logs":"..."} PYTHON → RUST: {"status":"pending","action":"continue","message":"Tests failed, refining..."} ... (iterations) ... PYTHON → RUST: {"status":"success","action":"stop","message":"Issue resolved!"}
Example 3: Error Handling
terminalRUST → PYTHON: {"command":"plan","issue_id":1} PYTHON → RUST: {"status":"error","action":"stop","message":"Failed to fetch issue: API key missing","logs":"...traceback..."} RUST displays error and exits
Encoding
- ▶Character Encoding: UTF-8
- ▶JSON Spec: RFC 7159
- ▶Line Terminator: LF () on Unix/Linux/macOS, CRLF (terminal
\n) OK but LF preferredterminal\r\n
Timeout Behavior
Rust Timeout Detection
If no response received for 30 seconds:
- ▶Log timeout message
- ▶Kill Python subprocess
- ▶Restart Python engine
- ▶Retry last request once
- ▶If still no response after 30s → exit with error
Python Timeout Prevention
Python should send a response within reasonable time (< 5s for most operations).
For long operations:
- ▶Send periodic messagesterminal
pending - ▶Or implement streaming (future enhancement)
Error Handling
Python Errors
If Python encounters an error processing a request:
json{ "status": "error", "action": "stop", "message": "Description of what failed", "logs": "... traceback to stderr ..." }
Rust Errors
If Rust encounters an error:
- ▶Log the error
- ▶Skip to next command
- ▶Or restart Python if critical
JSON Parse Errors
If either side receives invalid JSON:
- ▶Log the error to stderr
- ▶Send error response if possible
- ▶Or abort current operation
Performance Guidelines
- ▶Parse Speed: NDJSON parsing should be < 1ms per message
- ▶Flush Timing: Flush within 100ms of write
- ▶Message Size: Keep messages < 1MB (practical limit)
- ▶Latency: Aim for < 100ms roundtrip for simple operations
Versioning
Current protocol version: 1.0
Protocol changes require coordination between Rust and Python versions.
Testing
Manual Test (Python Engine)
bashecho '{"command":"plan","issue_id":1}' | python3 -m voria.engine
Expected output:
terminal{"status":"success","action":"stop","message":"Plan generated for issue #1"}
Manual Test (Full CLI)
bash./target/debug/voria -v plan 1
Expected behavior:
- ▶[i] Planning fix for issue #1
- ▶[✓] Plan generated for issue #1
- ▶Process exits cleanly
Debugging
Enable verbose logging:
bashRUST_LOG=debug ./target/debug/voria plan 1
This shows:
- ▶JSON being sent to Python
- ▶JSON being received from Python
- ▶Timing information
- ▶Process lifecycle events
View Python logs:
bash./target/debug/voria -v plan 1 2>&1 | grep -E "\[DEBUG\]|\[INFO\]"
Backward Compatibility
Currently no versioning mechanism. Once protocol is stable, add version field:
json{ "version": "1.0", "command": "...", ... }
Join our WhatsApp Support Group: Click Here