Elyra
Elyra The coding agent eTerm The terminal that knows where each command ends Huskarl AI colleagues on your own Mac Starf An activity monitor for Apple silicon that never invents a number etrans An SSH and SFTP client for macOS Elyra VM Virtual machines for macOS, Linux and Windows on your Mac Litr A small, native web browser for macOS Notr A notebook for macOS e The native code editor Elyra Grove Native local development environment Askr The real server for Laravel & PHP Elyra Framework Rust + Svelte 5 framework for desktop apps Elyra Conductor Local project conductor Refr Local-first PDF workspace for macOS Elyra Workspace A desktop workspace for coding agents Elyra SQL Server MySQL-compatible SQL server in Rust Elyra Félagi Agents as teammates on one board Elyra SQL Client Native desktop SQL workbench Elyra SQL Anywhere Replication-ready SQL engine Elyra Sjá SEO & GEO workspace for macOS Elyra DataGrid Server-driven data grid for Laravel
Development
Development
Release notes
Changelog
Elyra
JSON Event Stream Mode

JSON Event Stream Mode

elyra --mode json "Your prompt"

Outputs all session events as JSON lines to stdout. Useful for integrating elyra into other tools or custom UIs.

The prompt can also be piped on stdin, which keeps it out of the process list:

echo "Your prompt" | elyra --mode json

To continue an earlier session, pass its id (or a unique prefix) or file path with --session. --resume takes no value; it opens an interactive picker and needs a terminal.

echo "Now add tests" | elyra --mode json --session 01a15593

Run it from the directory the session was created in. A session id that only matches a session from another directory exits with code 1; use --fork <id> to continue it in the current directory.

Event Types

Events are defined in AgentSessionEvent:

type AgentSessionEvent =
  | AgentEvent
  | { type: "queue_update"; steering: readonly string[]; followUp: readonly string[] }
  | { type: "compaction_start"; reason: "manual" | "threshold" | "overflow" | "mid-turn" }
  | { type: "compaction_end"; reason: "manual" | "threshold" | "overflow" | "mid-turn"; result: CompactionResult | undefined; aborted: boolean; willRetry: boolean; errorMessage?: string }
  | { type: "auto_retry_start"; attempt: number; maxAttempts: number; delayMs: number; errorMessage: string }
  | { type: "auto_retry_end"; success: boolean; attempt: number; finalError?: string }
  | { type: "session_info_changed"; name: string | undefined }
  | { type: "thinking_level_changed"; level: ThinkingLevel }
  | { type: "decisions_extracted"; recorded: { id: string; title: string }[]; candidates: { title: string }[] }
  | { type: "smart_routing"; tier: ComplexityTier; reason: string; fromModel: string; toModel: string };

queue_update emits the full pending steering and follow-up queues whenever they change. compaction_start and compaction_end cover both manual and automatic compaction. Consumers should ignore event types they do not recognize; new ones are added over time.

Base events from AgentEvent:

type AgentEvent =
  // Agent lifecycle
  | { type: "agent_start" }
  | { type: "agent_end"; messages: AgentMessage[] }
  // Turn lifecycle
  | { type: "turn_start" }
  | { type: "turn_end"; message: AgentMessage; toolResults: ToolResultMessage[] }
  // Message lifecycle
  | { type: "message_start"; message: AgentMessage }
  | { type: "message_update"; message: AgentMessage; assistantMessageEvent: AssistantMessageEvent }
  | { type: "message_end"; message: AgentMessage }
  // Tool execution
  | { type: "tool_execution_start"; toolCallId: string; toolName: string; args: any }
  | { type: "tool_execution_update"; toolCallId: string; toolName: string; args: any; partialResult: any }
  | { type: "tool_execution_end"; toolCallId: string; toolName: string; result: any; isError: boolean };

Message Types

Base messages from packages/ai/src/types.ts:

  • UserMessage (line 134)
  • AssistantMessage (line 140)
  • ToolResultMessage (line 152)

Extended messages from packages/coding-agent/src/core/messages.ts:

  • BashExecutionMessage (line 29)
  • CustomMessage (line 46)
  • BranchSummaryMessage (line 55)
  • CompactionSummaryMessage (line 62)

Output Format

Each line is a JSON object. The first line is the session header:

{"type":"session","version":3,"id":"uuid","timestamp":"...","cwd":"/path"}

Followed by events as they occur:

{"type":"agent_start"}
{"type":"turn_start"}
{"type":"message_start","message":{"role":"assistant","content":[],...}}
{"type":"message_update","message":{...},"assistantMessageEvent":{"type":"text_delta","delta":"Hello",...}}
{"type":"message_end","message":{...}}
{"type":"turn_end","message":{...},"toolResults":[]}
{"type":"agent_end","messages":[...]}

Reading a Run

  • Session id: only in the header (id), the first line. Events do not repeat it.
  • Tool calls: tool_execution_start has toolName and args; tool_execution_end has result.content[] and isError.
  • Final answer: there is no separate result event. Use agent_end.messages: the last assistant message holds the answer in content[] (blocks with type: "text"). With automatic retry, a failed attempt ends with its own agent_end; the last one is the outcome.
  • Failure: the last assistant message has stopReason "error" or "aborted" and an errorMessage. The process then exits with code 1 and writes the error to stderr.
  • Cost: each assistant message carries usage (input, output, cacheRead, cacheWrite, cost.total in USD, already priced). Tools that call a model themselves (oracle, read_session) report it as details.modelUsage on their toolResult message. Sum both for the cost of a run.
  • message_update fires for every streamed chunk; most consumers only need message_end.

Example

elyra --mode json "List files" 2>/dev/null | jq -c 'select(.type == "message_end")'