Event Schema

June 16, 2026 · View on GitHub

Every CANarchy command that produces structured output emits events using a canonical envelope. This document defines that envelope and every typed event subclass.

The event schema is the stable interface between CANarchy and downstream consumers: scripts, pipelines, analysis tools, and coding agents. If you are parsing CANarchy output programmatically, parse the event stream rather than the human-readable text output.

Canonical Envelope

All events share the same top-level shape:

{
  "event_type": "<string>",
  "source": "<string>",
  "timestamp": "<float | null>",
  "payload": { }
}
FieldTypeDescription
event_typestringDiscriminator. See event types below.
sourcestringDotted path identifying which command or subsystem emitted the event. Examples: transport.capture, dbc.decode, gateway.src->dst.
timestampfloat | nullSeconds since epoch (or relative to capture start). null when not available.
payloadobjectEvent-specific fields. Shape varies by event_type.

Structured Errors

Failures return the canonical envelope with ok: false and an errors array. Each entry has code, message, and hint:

{
  "ok": false,
  "command": "decode",
  "errors": [
    {
      "code": "DBC_CACHE_MISS",
      "message": "DBC 'opendbc:toyota_tnga_k_pt_generated' is not in the local cache.",
      "hint": "Run `canarchy dbc cache refresh --provider opendbc` to populate it, or set `auto_refresh = true` under `[dbc.providers.opendbc]` in `~/.canarchy/config.toml`."
    }
  ]
}

Hint convention

Every structured error carries a non-empty hint. Hints follow a consistent shape — DBC_CACHE_MISS above is the reference template:

  • Explain the problem in one sentence.
  • Provide a copy-pasteable remediation command where one exists.
  • Reference the relevant flag, config key, or doc page by name.
  • Avoid restating the message; the hint is the next action.

A regression test (tests/test_cli.py::ErrorHintConventionTests) scans every ErrorDetail(...) call site in src/canarchy/ and asserts that each construction includes a hint=. Drift fails CI. Treat the catalogue in Troubleshooting as the user-facing index of these hints.

Streaming

Use --jsonl on any command to receive one event per line on stdout, suitable for piping:

canarchy capture can0 --jsonl
canarchy j1939 decode --file trace.candump --jsonl
canarchy generate can0 --count 100 --gap 10 --jsonl

Use --json to receive the full command envelope with all events in a data.events array:

canarchy capture can0 --json

Event Types

frame

A raw CAN frame, as captured, generated, or forwarded.

Emitted by: capture, send, generate, gateway, filter, replay

{
  "event_type": "frame",
  "source": "transport.capture",
  "timestamp": 0.0,
  "payload": {
    "frame": {
      "arbitration_id": 419360305,
      "bitrate_switch": false,
      "data": "11223344",
      "dlc": 4,
      "error_state_indicator": false,
      "frame_format": "can",
      "interface": "can0",
      "is_error_frame": false,
      "is_extended_id": true,
      "is_remote_frame": false,
      "timestamp": 0.0
    }
  }
}

Frame fields:

FieldTypeDescription
arbitration_idint11-bit standard (0–2047) or 29-bit extended (0–536870911) CAN identifier.
datastringHex-encoded payload bytes, lowercase, no separators.
dlcintData length code: number of payload bytes (0–8 for classic CAN, 0–64 for CAN FD).
frame_format"can" | "can_fd"Frame type.
interfacestring | nullInterface name such as can0 or 239.0.0.1.
is_extended_idbooltrue for 29-bit extended identifiers.
is_remote_framebooltrue for RTR frames (no data bytes).
is_error_framebooltrue for CAN error frames.
bitrate_switchboolCAN FD only — BRS flag.
error_state_indicatorboolCAN FD only — ESI flag.
timestampfloat | nullFrame timestamp, seconds.

Source values for frame events:

SourceContext
transport.captureCapture via the selected transport backend (python-can or scaffold)
transport.sendActive frame transmission
transport.generateFrame generation (canarchy generate)
transport.filterFile-backed filter result
gateway.src->dstForwarded frame, source to destination
gateway.dst->srcForwarded frame, destination to source (bidirectional mode)
replay.engineReplay plan frame

decoded_message

A CAN frame decoded against a DBC message definition. Includes the raw frame and all decoded signal values.

Emitted by: decode

{
  "event_type": "decoded_message",
  "source": "dbc.decode",
  "timestamp": 0.0,
  "payload": {
    "frame": { },
    "message_name": "EngineStatus1",
    "signals": {
      "CoolantTemp": -23,
      "LampState": 68,
      "Load": 20.4,
      "OilTemp": -6
    }
  }
}
FieldTypeDescription
frameobjectRaw CanFrame payload (same shape as frame event).
message_namestringDBC message name.
signalsobjectSignal name → decoded physical value map.

signal

An individual decoded signal value. One signal event is emitted per signal per decoded frame, immediately following its parent decoded_message event in the stream.

Emitted by: decode

{
  "event_type": "signal",
  "source": "dbc.decode",
  "timestamp": null,
  "payload": {
    "message_name": "EngineStatus1",
    "signal_name": "CoolantTemp",
    "units": "degC",
    "value": -23
  }
}
FieldTypeDescription
message_namestring | nullParent DBC message name.
signal_namestringDBC signal name.
unitsstring | nullPhysical unit string from the DBC (empty string if not defined).
valuenumberDecoded physical value after scaling and offset.

dbc_database

A DBC database summary emitted by dbc inspect before message and signal metadata.

Emitted by: dbc inspect

{
  "event_type": "dbc_database",
  "source": "dbc.inspect",
  "timestamp": null,
  "payload": {
    "format": "dbc",
    "message_count": 2,
    "node_count": 0,
    "path": "tests/fixtures/sample.dbc",
    "signal_count": 6
  }
}

dbc_message

DBC message metadata emitted by dbc inspect.

Emitted by: dbc inspect

When dbc inspect --layout is used, the payload also includes string fields layout, signal_tree, and signal_choices rendered by cantools.

{
  "event_type": "dbc_message",
  "source": "dbc.inspect",
  "timestamp": null,
  "payload": {
    "arbitration_id": 419360305,
    "arbitration_id_hex": "0x18FEEE31",
    "cycle_time_ms": null,
    "is_extended_id": true,
    "length": 4,
    "name": "EngineStatus1",
    "senders": [],
    "signal_count": 4
  }
}

dbc_signal

DBC signal metadata emitted by dbc inspect.

Emitted by: dbc inspect

{
  "event_type": "dbc_signal",
  "source": "dbc.inspect",
  "timestamp": null,
  "payload": {
    "byte_order": "little_endian",
    "choices": null,
    "is_multiplexer": false,
    "is_signed": false,
    "length": 8,
    "maximum": 210,
    "message_name": "EngineStatus1",
    "minimum": 0,
    "multiplexer_ids": null,
    "name": "CoolantTemp",
    "offset": -40,
    "scale": 1,
    "start_bit": 0,
    "unit": "degC"
  }
}

j1939_pgn

A J1939 frame observation with decomposed identifier fields.

Emitted by: j1939 monitor, j1939 decode, j1939 pgn

{
  "event_type": "j1939_pgn",
  "source": "transport.j1939.decode",
  "timestamp": 0.0,
  "payload": {
    "destination_address": null,
    "frame": { },
    "pgn": 65262,
    "priority": 6,
    "source_address": 49
  }
}
FieldTypeDescription
pgnintParameter Group Number (0–262143).
source_addressintJ1939 source address (0–255).
destination_addressint | nullPeer-to-peer destination address, or null for broadcast PGNs.
priorityint | nullJ1939 frame priority (0–7).
frameobjectRaw CanFrame payload.

j1587_parameter

A decoded J1587 PID parameter extracted from a J1708 message.

Emitted by: j1587 decode

{
  "event_type": "j1587_parameter",
  "source": "j1587",
  "timestamp": 0.0,
  "payload": {
    "checksum_valid": true,
    "mid": 128,
    "name": "Engine Speed",
    "pid": 190,
    "raw": "7017",
    "units": "rpm",
    "value": 1500.0
  }
}
FieldTypeDescription
midintSource MID (0–255) from the J1708 message.
pidintJ1587 Parameter ID (0–511; values above 253 use the extended-PID encoding).
rawstringRaw parameter data bytes as hex.
namestring | nullParameter name from the bundled PID catalog, or null if unknown.
valuefloat | nullScaled value, or null if unknown or the all-ones "data not available" sentinel.
unitsstring | nullUnits from the bundled PID catalog, or null if unknown.
checksum_validboolWhether the source J1708 message's byte-sum checksum was valid.

j2497_message

A decoded J2497 (PLC4TRUCKS trailer power-line) frame.

Emitted by: j2497 decode

{
  "event_type": "j2497_message",
  "source": "j2497",
  "timestamp": 0.0,
  "payload": {
    "checksum_valid": true,
    "data": "2c01",
    "mid": 137,
    "name": "Brakes - Trailer #1 (ABS)"
  }
}
FieldTypeDescription
midintSource MID (0–255) from the J2497 frame.
datastringMessage-data bytes (between the MID and the checksum) as hex.
namestring | nullECU name from the bundled MID catalog, or null if unknown.
checksum_validboolWhether the frame's byte-sum checksum was valid.

uds_transaction

A UDS request/response pair observed during a scan or trace.

Emitted by: uds scan, uds trace

{
  "event_type": "uds_transaction",
  "source": "transport.uds.scan",
  "timestamp": 0.0,
  "payload": {
    "complete": true,
    "decoder": "built-in",
    "ecu_address": 2024,
    "negative_response_code": null,
    "negative_response_name": null,
    "request_data": "1001",
    "request_id": 2015,
    "request_summary": null,
    "response_data": "5001003201f4",
    "response_id": 2024,
    "response_summary": null,
    "service": 16,
    "service_name": "DiagnosticSessionControl"
  }
}
FieldTypeDescription
serviceintUDS service ID (hex values: 0x10 = DiagnosticSessionControl, 0x22 = RDBI, etc.).
service_namestringHuman-readable service name.
request_idintCAN arbitration ID of the request frame.
response_idintCAN arbitration ID of the response frame.
ecu_addressint | nullResponding ECU address (typically equals response_id).
request_datastringRequest payload bytes, hex-encoded.
response_datastringResponse payload bytes, hex-encoded.
completebooltrue when the response payload was fully reassembled; false when the capture ended early or consecutive frames arrived out of order.
decoderstringProtocol decoder path used for transaction enrichment, such as built-in or scapy.
request_summarystring | nullOptional summary-level request interpretation when the Scapy-backed adapter is available.
response_summarystring | nullOptional summary-level response interpretation when the Scapy-backed adapter is available.
negative_response_codeint | nullNegative response code for UDS negative responses.
negative_response_namestring | nullHuman-readable negative response name for UDS negative responses.

replay_event

A scheduled frame transmission from a replay plan.

Emitted by: replay

{
  "event_type": "replay_event",
  "source": "replay.engine",
  "timestamp": 0.0,
  "payload": {
    "action": "send_frame",
    "frame": { },
    "rate": 1.0
  }
}
FieldTypeDescription
actionstring"send_frame" for frame transmission events; "plan_start" / "plan_end" for lifecycle events.
ratefloat | nullReplay rate multiplier (1.0 = original timing, 2.0 = double speed).
frameobject | nullRaw CanFrame payload (absent for lifecycle events).

alert

A diagnostic notice from a command: active-transmit warnings, backend availability notices, or informational messages.

Emitted by: send, generate, gateway, and any command that raises a notable condition.

{
  "event_type": "alert",
  "source": "transport.generate",
  "timestamp": null,
  "payload": {
    "code": "ACTIVE_TRANSMIT",
    "level": "warning",
    "message": "Active frame generation requested on the selected interface."
  }
}
FieldTypeDescription
level"info" | "warning" | "error"Severity.
codestring | nullMachine-readable alert code.
messagestringHuman-readable description.

Common alert codes:

CodeLevelContext
ACTIVE_TRANSMITwarningFrame generation or active transmission requested.
CANDUMP_LIVE_BACKEND_REQUIREDerror--candump mode requires python-can backend.
GATEWAY_LIVE_BACKEND_REQUIREDerrorgateway requires python-can backend.

Consuming Events in Scripts

Parse JSONL output line by line and filter on event_type:

# Extract all frame arbitration IDs from a live capture
canarchy capture can0 --jsonl \
  | jq 'select(.event_type == "frame") | .payload.frame.arbitration_id'

# Decode a trace and print each signal value
canarchy decode --file trace.candump --dbc vehicle.dbc --jsonl \
  | jq 'select(.event_type == "signal") | [.payload.signal_name, .payload.value, .payload.units]'

# Watch for J1939 coolant temperature observations
canarchy j1939 decode --file trace.candump --jsonl \
  | jq 'select(.event_type == "j1939_pgn" and .payload.pgn == 65262)'

Agent Integration

See Agent Guide for how to invoke CANarchy commands as a coding agent and parse structured results.