
How the AxiOwl CLI Works With JSON Input
JSON matters in AxiOwl, but the current CLI is not a single "send this JSON request" interface. The C++ implementation separates human shell commands, raw message bodies, structured worker files, relay frames, MCP JSON-RPC, and machine-readable output. That distinction is useful for operators because it keeps message text from being accidentally reinterpreted as control data.
In plain terms: axiowl send and axiowl create accept command-line options plus optional raw stdin for message text. JSON input is supported on narrower protocol surfaces such as delivery-worker --request, relay-session --stdio, and mcp-server. discover --json is JSON output, not JSON input.
Sources read
Source repo: C:\Users\kjhgf\OneDrive\Documents\postfourth\axiowl-cplus
README.mdapps/windows-desktop/README.mdapps/windows-desktop/CMakeLists.txtapps/windows-desktop/src/main.cppapps/windows-desktop/src/cli.cppapps/windows-desktop/src/cli.hppapps/windows-desktop/src/string_util.cppapps/windows-desktop/src/json_util.cppapps/windows-desktop/src/json_util.hppapps/windows-desktop/src/mcp_server.cppapps/windows-desktop/src/delivery_worker.cppapps/windows-desktop/src/remote_relay.cppapps/windows-desktop/src/message_pipeline.cppapps/windows-desktop/src/evidence_log.cppapps/windows-desktop/src/models.hppapps/windows-desktop/src/discovery.cppapps/windows-desktop/src/discovery.hppapps/windows-desktop/tests/core_tests.cppdocs/plans/04-local-service-and-cli.mddocs/plans/10-receipts-errors-and-logging.mddocs/plans/15-mcp-refactor-final-plan.mddocs/plans/16-cli-providers-release-and-integration.md- Built CLI help checked with
build\Release\axiowl.exe --helpand--version
Normal Send Input Is Text
The active help output shows two supported shapes for sending:
axiowl send --to <agent> --body <message> [--from <agent>] [--from-node <node>] [--strict] [--run-id <uuid>] [--delivery-method <cursor-method|A|B|C|D|E>]
axiowl send --to <agent> --stdin [--from <agent>] [--from-node <node>] [--strict] [--run-id <uuid>] [--delivery-method <cursor-method|A|B|C|D|E>]
The parser in cli.cpp reads --to, --body, --run-id, --strict, --delivery-method, --source-context, --from, and --from-node from argv. If --stdin is present, it replaces the body with read_all_stdin(). That function reads the stdin stream as text and returns it unchanged.
That means stdin is a body channel, not a JSON request channel. If an operator pipes this into axiowl send --stdin:
{"to":"Target","body":"Hello"}
AxiOwl treats the entire JSON string as the message body. It does not extract to or body from that text. The target still has to come from --to, and sender identity still has to resolve through the registry or explicit sender options.
The same pattern applies to create:
axiowl create --provider <provider> --name <agent> [--body <message> | --stdin] [--from <agent>] [--from-node <node>] [--model <model>] [--cwd <cwd>]
create can accept an initial body through --body or raw stdin. It does not accept a JSON object that contains provider, name, and body. For most shell automation, this is the right model: keep routing fields in argv and put only the potentially large, multiline, quote-heavy content in stdin.
Where JSON Input Does Exist
AxiOwl does accept JSON input, but only on specific command surfaces that are written as protocols or internal worker boundaries.
delivery-worker --request <request-json-file> reads a JSON file whose type field must be delivery_worker_request. The worker file includes fields such as run_id, message_id, target_display_name, target_provider, target_provider_session_id, sender_agent, sender_node, final_visible_body, requested_delivery_method, and strict. The delivery worker can also run --validate-only, which parses and validates the request without dispatching the provider edge.
This is a real JSON input mode, but it is not the normal public send command. The send pipeline writes these request files as handoff artifacts and starts the delivery worker after AxiOwl has already accepted the message, resolved the sender, resolved the target, built the final visible body, and recorded receipt evidence.
relay-session --stdio is another JSON input mode. It starts with a JSON hello response and then reads line-delimited JSON frames from stdin. A deliver frame can include fields such as request_id, target, body, strict, body_is_final_visible, direct target provider fields, and sender identity fields. The relay emits JSON result frames such as deliver_result or error.
This is the remote relay protocol. It is useful when a remote AxiOwl endpoint needs to receive structured delivery frames over stdio, but it is not the same as adding JSON request parsing to axiowl send.
mcp-server is the most important structured input surface for agent hosts. It reads MCP JSON-RPC messages over stdin. The implementation supports regular line input and Content-Length framed input. It handles initialize, ping, tools/list, and tools/call.
The MCP tool schema advertises typed tools including:
axiowl_send_message, requiringtoandbody, with optionalstrict,runId,receiptForMessageId, andsourceContext.axiowl_create_agent, requiringproviderandname, with optionalbody,model, andcwd.axiowl_discover, requiringprovider, with optionaltarget,node, andjson.- Registry and node helper tools.
axiowl_relay_deliver, which builds one relaydeliverframe.
For axiowl_send_message, the MCP layer reads JSON-RPC tool arguments, resolves host sender identity from MCP metadata, registers the sender when possible, and then calls the normal CLI path with send --to ... --stdin. The JSON is the typed host protocol; the underlying send body still flows through stdin as raw message text.
JSON Output Is A Separate Feature
discover --json is easy to misread as a JSON input mode. It is not. In cli.cpp, run_discover checks for --json and then prints the discovery report through format_discovery_report_json_lines. Without --json, it prints human-readable text.
The JSON discovery output includes row details and a summary line. It is meant for scripts and MCP calls that need machine-readable discovery results. The input to discovery remains argv:
axiowl discover <provider-or-all> [--target <agent>] [--json]
AxiOwl also writes JSONL evidence logs. EvidenceLog::append writes one JSON object per line with event_type, created_at, and event fields. The message pipeline logs stages such as request acceptance, target resolution, route resolution, and delivery worker handoff. Delivery worker results are also printed as JSON objects. These are reporting and audit surfaces, not alternate command parsers.
The Parser Boundary Is Intentional
The shared json_util helper is deliberately small. It parses flat JSON objects, string fields, escaped strings, and boolean-like values. Tests cover this with a flat object containing type, body, and ok. That helper is enough for delivery worker files, activation/status snippets, and simple provider result records.
The MCP server has its own raw object extraction helpers for nested JSON-RPC messages. It can pull out nested params, arguments, and metadata fields while preserving raw JSON tokens where needed. That separate parser exists because MCP messages are nested protocol messages, while ordinary CLI commands are simple argv commands.
This boundary prevents a common class of automation bugs. A message body can contain JSON, code, logs, or arbitrary quoted text without AxiOwl trying to treat it as control input. When AxiOwl does expect control input, the command surface says so explicitly: a request JSON file, a relay JSON line, or an MCP JSON-RPC frame.
Practical Operator Rules
Use --body for short messages.
Use --stdin for long messages, multiline text, code blocks, JSON samples, or anything with quotes that would be awkward to escape through the shell.
Use mcp-server when a host app or agent runtime should call AxiOwl through typed JSON-RPC tools and provide sender identity metadata.
Use discover --json when a script needs machine-readable discovery output.
Use delivery-worker --request only when you are working at the delivery worker boundary and have the full delivery_worker_request file shape.
Use relay-session --stdio only when you are speaking the relay protocol with JSON-line frames.
Do not assume a general send --json or create --json flag exists in the current CLI. It does not appear in the source parser or the current help output.
Why This Matters
AxiOwl's current CLI design keeps responsibility split cleanly. The command line names the operation and routing options. Stdin carries the human-visible message body. The message pipeline resolves sender and target identity, builds the final visible body, returns an AxiOwl receipt, and starts the delivery worker. JSON is used where structure is necessary: MCP tool calls, relay frames, worker requests, discovery output, and JSONL evidence.
That makes the system easier to automate without weakening its receipt model. A send receipt means the request reached AxiOwl and passed the boundary stated in the receipt. It does not imply that the receiver replied, and in the normal fast path it does not claim provider delivery before the worker has proven it. JSON support follows the same rule: every structured path has a defined boundary, and unsupported JSON input modes are left unsupported rather than guessed.
Image prompt:
Create a polished graphic image related to: AxiOwl CLI JSON input.
Subject: a terminal window beside floating structured JSON blocks and a narrow stdin pipe entering a command prompt, with no readable characters or symbols that form words.
Style: halfway between a clean symbolic icon and a realistic product/technical illustration; professional SaaS/technical marketing style; crisp edges; high detail; no text; no logos.
Background: solid #00ff00 chroma key green screen background covering the full canvas edge to edge.
Restrictions: no owl, no axolotl, no birds, no animals, no mascot, no text, no watermark.