Envelopes
Every murli output method writes a JSON envelope to stdout or stderr. The envelope shape is consistent across all language implementations and all versions within the 1.x series.
Success envelope
Written by WriteSuccess(humanText, jsonPayload).
{
"status": "ok",
"schema_version": "1.0",
"tool_version": "1.0.2",
"message": "Found 1 result",
"result": { ... }
}
| Field | Value |
|---|---|
| status | Always "ok" |
| schema_version | Always "1.0" in the v1.x series |
| tool_version | Value of murli.ToolVersion. Empty string if not set at build time. |
| message | The humanText argument to WriteSuccess |
| result | The jsonPayload argument, marshalled as JSON. null if nil. |
Error envelope
Written to stderr by WriteError(err). The process exits with err.Code immediately after writing.
{
"status": "error",
"code": 1,
"error": "user_error",
"message": "flag --top: invalid value \"abc\" for int flag",
"suggestion": "Valid values are 5, 10, 20, 50.",
"valid_values": ["5", "10", "20", "50"],
"recoverable": true,
"retry_after_ms": 0,
"schema_version": "1.0",
"tool_version": "1.0.2"
}
| Field | Always present | Notes |
|---|---|---|
| status | Yes | Always "error" |
| code | Yes | Exit code (0–9). See Exit codes. |
| error | Yes | Machine-readable error category string |
| message | Yes | Human-readable description |
| suggestion | No | What to do next |
| valid_values | No | Acceptable values when an enum was violated |
| recoverable | Yes | Whether retrying the same call may succeed |
| retry_after_ms | No | Milliseconds to wait before retrying (rate-limit errors) |
| field | No | Flag or argument that caused the error |
| doc_url | No | Link to relevant documentation |
| schema_version | Yes | Always "1.0" |
| tool_version | Yes | Value of murli.ToolVersion |
Plan envelope
Written by WritePlan(humanText, plan) when the handler detects w.IsDryRun() == true.
{
"status": "plan",
"schema_version": "1.0",
"tool_version": "1.0.2",
"message": "Would delete 3 files",
"plan": {
"would_delete": ["/tmp/a.db", "/tmp/b.db", "/tmp/c.db"],
"count": 3
}
}
Event envelope (NDJSON)
Written by WriteEvent(v). One JSON object per line on stdout. Agents should read stdout line by line and parse each line as a separate JSON object.
{"event":"chunk","index":0,"data":"first batch of results"}
{"event":"chunk","index":1,"data":"second batch of results"}
{"status":"ok","schema_version":"1.0","tool_version":"1.0.2","message":"Done","result":{"total":2}}
The final line is always a success or error envelope. Intermediate lines are application-defined event objects.
Progress envelope (NDJSON)
Written by WriteProgress(evt) when in agent mode. In TTY mode, progress is written as plain text to stderr instead.
{"event":"progress","stage":"read","current":1,"total":3,"percent":33,"message":"reading corpus"}
{"event":"progress","stage":"embed","current":2,"total":3,"percent":66,"eta_ms":4200}
{"event":"progress","stage":"write","current":3,"total":3,"percent":100}
{"status":"ok","schema_version":"1.0","tool_version":"1.0.2","message":"Reindexed 4213 docs","result":{"count":4213}}