Skip to content

Command Spec

Status

This document describes the current implemented CLI contract.

Implemented and verified in the current codebase:

  • live and deterministic transport workflows for capture, send, generate, and simulate
  • file-backed filter, stats, compare, and capture-info over candump capture logs
  • default python-can support for capture and send
  • deterministic replay and sequence replay
  • live gateway bridging between CAN interfaces via python-can
  • structured export for capture files and saved sessions
  • DBC-backed decode, encode, and dbc inspect
  • DBC provider workflows for dbc provider list, dbc search, dbc fetch, dbc cache list, dbc cache prune, and dbc cache refresh
  • dataset provider workflows for datasets provider list, datasets search, datasets inspect, datasets fetch, datasets download, datasets cache list, datasets cache refresh, datasets convert, datasets stream, and datasets replay
  • J1939 monitor, decode, pgn, spn, tp, dm1, faults, summary, inventory, compare, and map
  • session save, load, and show
  • shell one-shot command execution
  • full-screen Textual tui dashboard over the shared command layer
  • UDS scan, trace, services, subservices, ecu-reset, tester-present, security-seed, dump-dids, read-memory, and auto
  • DoIP discovery, services, ecu-reset, tester-present, security-seed, and dump-dids for Diagnostic-over-IP workflows
  • XCP (measurement/calibration) scan, info, dump, trace, read, and commands for XCP-on-CAN
  • J1587/J1708 decode and pids for legacy heavy-vehicle diagnostic captures
  • J2497 (PLC4TRUCKS) decode and mids for passive trailer power-line frame captures
  • plot for decoded signal time-series rendering (optional [plot] extra)
  • config show for effective transport configuration inspection
  • re signals, re counters, re entropy, re correlate, re anomalies, and re corpus for passive file-backed analysis
  • re match-dbc and re shortlist-dbc for provider-backed DBC candidate ranking against captures
  • re suggest for heuristic signal-name suggestions (with an optional, off-by-default external-LLM enrichment)
  • plugins list, plugins info, plugins enable, and plugins disable for Python entry-point plugin inspection and toggles
  • web serve for the read-only browser dashboard over the JSONL event envelope
  • cannelloni decode and cannelloni send for cannelloni CAN-over-UDP wire-format interop
  • skills provider workflows for skills provider list, skills search, skills fetch, skills cache list, and skills cache refresh
  • active-transmit fuzz payload, fuzz replay, fuzz arbitration-id, fuzz signal, fuzz spn, fuzz guided, and fuzz identify, all gated by the active-transmit safety model
  • structured JSON and JSONL output
  • explicit error schema and exit codes

Important current behavior:

  • live transport-facing commands default to the python-can backend; set backend = "scaffold" in ~/.canarchy/config.toml or export CANARCHY_TRANSPORT_BACKEND=scaffold for deterministic offline behavior
  • capture, send, and gateway use the selected transport backend, but gateway specifically requires python-can
  • the default python-can interface is socketcan; set interface in the config file or CANARCHY_PYTHON_CAN_INTERFACE to change it
  • the default CAN interface/channel is optional; set default_interface in the config file or CANARCHY_DEFAULT_INTERFACE to let single-interface commands such as capture, send, generate, uds scan, and live fuzz commands omit the interface argument
  • DBC-backed commands accept local paths and provider refs such as opendbc:<name> or comma:<name>
  • database-backed commands (decode, encode, dbc inspect, dbc convert, …) also accept ARXML (.arxml), KCD (.kcd), and SYM (.sym) files in addition to DBC (.dbc); the format is selected by filename suffix through the cantools runtime, and the user-facing flag remains --dbc
  • decode, encode, and dbc inspect include data.dbc_source in structured output so callers can see the provider, logical DBC name, pinned version, resolved local path, and database kind (dbc / arxml / kcd / sym); dbc inspect additionally reports the same value as data.database.format
  • some protocol-oriented commands currently use explicit sample/reference providers rather than true transport-backed execution paths
  • specialized text formatting exists for J1939 monitor and decode style output; other --text output is generic key/value rendering
  • file-backed analysis commands support standard timestamped candump log files (.candump, .log) and pcap/pcapng files (.pcap, .pcapng) with CAN SocketCAN (DLT 227) frames; selected commands also support --file - for candump text from stdin
  • commands that historically took positional capture paths (the re * family and j1939 compare) also accept the --file <path> flag form (repeatable for multi-file commands); supplying both forms with different paths returns CONFLICTING_FILE_ARGUMENTS

Command Structure

Commands follow one of these patterns:

canarchy <domain> <action> [args]

or

canarchy <action> <object>

Examples:

  • canarchy capture can0 --json
  • canarchy capture --json when [transport].default_interface is configured
  • canarchy replay --file tests/fixtures/sample.candump --rate 2.0 --json
  • canarchy j1939 monitor --pgn 65262 --json
  • canarchy decode --file tests/fixtures/sample.candump --dbc tests/fixtures/sample.dbc --json

Implemented Commands

capture

Capture traffic from a local interface. Structured capture uses the selected transport backend. --candump is a live-only mode.

canarchy capture [interface] [--candump] [--json|--jsonl|--text]

Example:

canarchy capture can0 --json
canarchy capture vcan0 --candump

Notes:

  • --candump is a live-only mode that requires the python-can backend (set in ~/.canarchy/config.toml or via CANARCHY_TRANSPORT_BACKEND=python-can)
  • if interface is omitted, capture uses [transport].default_interface or CANARCHY_DEFAULT_INTERFACE; without either, it returns INTERFACE_REQUIRED
  • --candump keeps running and printing frames until interrupted
  • --candump changes the human-readable output path to a candump-style line format such as (0.100000) vcan0 18F00431#AABBCCDD
  • --candump --json and --candump --jsonl keep structured output for automation, but still require a live backend
  • default text output without --candump remains the generic key/value renderer

Supported file input today:

  • file-backed commands consume standard timestamped candump logs in the form (timestamp) interface frame#data
  • supported additional candump forms include classic RTR id#R, CAN FD id##<flags><data>, and error frames using a CAN error-flagged identifier
  • supported CAN FD flags today are the BRS and ESI bits in the single-nibble candump flags field
  • supported capture-file suffixes today are .candump, .log, .pcap, and .pcapng; --file - reads candump text from stdin for commands that explicitly support it
  • pcap/pcapng support requires the file to use the CAN SocketCAN linktype (DLT 227); files with other linktypes are rejected with a clear error
  • pcap/pcapng files are always fully scanned (no fast-scan estimation); the binary format does not support text-based head/tail estimation
  • malformed log lines are skipped during capture parsing rather than falling back to fixture data; commands that require capture metadata or explicitly validate stdin emptiness return structured errors when no valid frames are available

send

Prepare an active transmit frame.

canarchy send [interface] <frame-id> <hex-data> [--dry-run] [--ack-active] [--json|--jsonl|--text]

Example:

canarchy send can0 0x123 11223344 --json

Notes:

  • --ack-active requests an interactive YES confirmation before the frame is transmitted
  • --dry-run returns the planned frame without opening a transport or requiring confirmation
  • when active acknowledgement is required by configuration, omitting --ack-active returns a structured ACTIVE_ACK_REQUIRED error
  • if interface is omitted, send uses [transport].default_interface or CANARCHY_DEFAULT_INTERFACE; explicit command-line interfaces take precedence over the configured default

filter

Filter a capture source by a simple expression.

canarchy filter <expression> (--file <path> | --file - | --stdin) [--offset <n>] [--max-frames <n>] [--seconds <seconds>] [--json|--jsonl|--text]
Notes:

* `--file -` reads candump text from standard input instead of a file and still honors `--offset`, `--max-frames`, and `--seconds`
* `--stdin` reads JSONL `frame` events from standard input regardless of output format
* For `filter --stdin`, each line must be a valid `frame` event JSON object
* expression operands for `id==` / `pgn==` / `sa==` accept decimal, `0x`-prefixed hex, or bare hex, and all operators tolerate surrounding whitespace (e.g. `pgn == 61444`); `sa` matches the J1939 source address of extended frames only
* supported atoms: `all`, `id==<id>`, `pgn==<pgn>`, `sa==<address>`, `dlc><n>`, `data~=<hex>`, `extended`, `standard`, combined with `&&` / `||`
* on an invalid expression the JSON error envelope carries no `frames` / `frame_count` block, so an error can never read as a successful zero-match

### capture-info

Inspect a candump capture quickly before running deeper analysis.

```bash
canarchy capture-info --file <path> [--json|--jsonl|--text]
canarchy capture-info --file - [--json|--jsonl|--text]

Notes:

  • --file - reads candump text from standard input instead of a file
  • Returns capture metadata only:

  • frame_count

  • first_timestamp
  • last_timestamp
  • duration_seconds
  • unique_ids
  • interfaces
  • suggested_max_frames
  • suggested_seconds

stats

Summarize a capture source. The capture path may be given positionally or via --file (equivalent).

canarchy stats <path> [--top <n>] [--offset <n>] [--max-frames <n>] [--seconds <seconds>] [--json|--jsonl|--text]
canarchy stats --file <path> [--top <n>] [--offset <n>] [--max-frames <n>] [--seconds <seconds>] [--json|--jsonl|--text]
canarchy stats --file - [--top <n>] [--offset <n>] [--max-frames <n>] [--seconds <seconds>] [--json|--jsonl|--text]

The following passive analysis commands likewise accept a positional capture path as an alias for --file: stats, j1939 summary, j1939 faults, j1939 dm1, j1939 inventory, j1939 map, j1939 tp sessions, j1939 tp compare, j1587 decode, j2497 decode. Supplying both forms with different paths returns CONFLICTING_FILE_ARGUMENTS.

Notes:

  • --file - reads candump text from standard input instead of a file
  • beyond total_frames / unique_arbitration_ids, the payload reports duration_seconds, first/last timestamps, a dlc_distribution, and a bus_load block with total bits, bits/s, and load percentages at 250 k / 500 k / 1 M bit/s (frame overhead without stuff bits; a lower-bound estimate)
  • top_ids details the highest-frequency arbitration ids (default 20, bounded by --top): arbitration_id_hex, frame_count, share, rate_hz, mean/min/max inter-frame gap, gap_jitter_ms, observed DLCs, and first/last seen

compare

Diff two or more plain CAN captures per arbitration ID against a baseline, the generic-CAN analogue of j1939 compare.

canarchy compare (<file> <file> [<file> ...] | --file <file> --file <file> ...) [--baseline <path>] \
    [--top <n>] [--offset <n>] [--max-frames <n>] [--seconds <s>] [--json|--jsonl|--text]

Notes:

  • this command is passive and file-backed; it accepts two or more captures positionally or via repeatable --file, and requires at least two (COMPARE_NEEDS_FILES otherwise)
  • the baseline is the first file unless --baseline <path> designates another; a --baseline outside the compared set is folded in as the reference
  • each comparison entry reports, per (arbitration_id, is_extended_id) pair, the per-file frame_counts, rates_hz, mean_gap_ms, and mean_byte_entropy arrays, the frame_count_delta / rate_ratio / entropy_delta versus the baseline, a cycle_time_drift_ratio (reusing the re corpus drift formulation), a combined change_score, and a flags list (new-vs-baseline, dropped-vs-baseline, rate-drop, rate-spike, entropy-collapse, timing-drift)
  • entries are ranked by change_score and capped at --top (default 20; 0 for all); id_count reports the full total and returned_count the number returned
  • each row includes is_extended_id; standard and extended frames sharing a numeric ID remain separate, and only extended rows receive available J1939 annotations
  • id_count and summary.unique_ids count ID/type pairs; equal change scores sort by numeric ID, then standard before extended
  • the summary block retains sorted, deduplicated numeric arrays (new_ids, dropped_ids, rate_drop_ids, rate_spike_ids, entropy_collapse_ids, timing_drift_ids) for compatibility. Each has a parallel *_identifiers array (replace _ids with _identifiers) of objects such as {"arbitration_id": 291, "is_extended_id": true}. These arrays preserve type, sort by numeric ID then type, and include all findings regardless of --top
  • --offset, --max-frames, and --seconds bound each capture independently

generate

Generate CAN frames from explicit, random, or incrementing inputs.

canarchy generate [interface] [--id <hex|R>] [--dlc <0-8|R>] [--data <hex|R|I>] [--count <n>] [--gap <ms>] [--extended] [--dry-run] [--ack-active] [--json|--jsonl|--text]

Examples:

canarchy generate can0 --id 0x123 --dlc 4 --data 11223344 --count 2 --gap 100 --json
canarchy generate --id 0x123 --dlc 4 --data 11223344 --count 2 --dry-run --json
canarchy generate can0 --data I --count 4 --text
canarchy generate can0                              # runs until Ctrl-C, cangen-style

Notes:

  • --id, --dlc, and --data accept R for random generation, and --data I enables a deterministic incrementing payload pattern
  • omitting --count generates and transmits frames continuously, spaced by --gap, until interrupted (Ctrl-C) — matching cangen from can-utils; passing --count N generates exactly N frames and exits
  • --dry-run emits the planned generated frame events without requiring an interface or opening a transport; without --count a dry run plans a single frame
  • invocations that cannot receive Ctrl-C (e.g. the MCP server) must pass --count explicitly for a live (non-dry-run) run, or a structured MISSING_COUNT error is returned
  • --ack-active requests an interactive YES confirmation before generated frames are transmitted
  • when active acknowledgement is required by configuration, omitting --ack-active returns a structured ACTIVE_ACK_REQUIRED error
  • generated JSON output includes an active-transmit alert followed by generated frame events

simulate

Emit a deterministic, profile-driven mix of classic CAN, J1939, and DM1 traffic without hardware or an external generator.

canarchy simulate [interface] --profile {heavy-truck,passenger-car} [--rate <hz>] \
    [--duration <seconds>] [--seed <n>] [--dry-run] [--ack-active] [--json|--jsonl|--text]

Examples:

canarchy simulate --profile heavy-truck --duration 5 --dry-run --json
canarchy simulate vcan0 --profile passenger-car --rate 50 --seed 7 --ack-active --json

Notes:

  • profiles are data-driven JSON resources (canarchy/resources/simulate/profiles.json); frame mix, weights, and DM1 bursts are defined there, so new archetypes need no code changes
  • deterministic and seedable via --seed; timestamps are spaced at 1 / --rate
  • --dry-run plans the frame mix without transmitting; live transmission honors the active-transmit safety model (--ack-active, YES confirmation, [safety].require_active_ack)
  • reuses the existing transport backends, including socketcan virtual interfaces, udp_multicast, and stdout candump piping
  • structured errors: SIMULATE_INVALID_RATE, SIMULATE_INVALID_DURATION

replay

Replay a capture source with deterministic timing derived from relative frame timestamps. By default this returns a replay plan (planning mode). When --interface is specified, frames are transmitted onto a live CAN bus with capture timing.

canarchy replay --file <path> [--interface <iface>] [--rate <factor>] [--dry-run] [--ack-active] [--json|--jsonl|--text]

Examples:

canarchy replay --file tests/fixtures/sample.candump --rate 2.0 --json
canarchy replay --file tests/fixtures/sample.candump --interface vcan0 --rate 1.0 --ack-active --json
canarchy replay --file tests/fixtures/sample.candump --interface vcan0 --dry-run --json

gateway

Bridge frames from one live CAN interface to another through the python-can backend.

canarchy gateway <src> <dst> [--src-backend <type>] [--dst-backend <type>] [--bidirectional] [--count <n>] [--dry-run] [--ack-active] [--json|--jsonl|--text]

Examples:

canarchy gateway can0 can1 --text
canarchy gateway can0 can1 --dry-run --json
canarchy gateway can0 239.0.0.1 --dst-backend udp_multicast --count 10 --json

Notes:

  • gateway requires the python-can backend (set in ~/.canarchy/config.toml or via CANARCHY_TRANSPORT_BACKEND=python-can)
  • --src-backend and --dst-backend default to the configured interface value
  • --dry-run returns the forwarding plan without opening either transport
  • --ack-active requests an interactive YES confirmation before forwarding begins
  • default text output use candump-style forwarded frame lines with direction labels such as [src->dst]
  • --json returns a standard command envelope; --jsonl emits one forwarded event per line for gateway

export

Export structured artifacts for later analysis.

canarchy export <source> <destination> [--json|--jsonl|--text]

Examples:

canarchy export tests/fixtures/sample.candump artifacts/sample.json --json
canarchy export tests/fixtures/sample.candump artifacts/sample.jsonl --json
canarchy export session:lab-a artifacts/session.json --json

Notes:

  • capture file sources use .candump or .log paths
  • saved sessions use the explicit session:<name> source form
  • destination .json writes a full structured artifact envelope
  • destination .jsonl writes one serialized event per line and is only supported for event-capable sources such as capture files

decode

Decode frames from a capture source using a DBC file.

canarchy decode --file <file> --dbc <file> [--json|--jsonl|--text]
canarchy decode --stdin --dbc <file> [--json|--jsonl|--text]

Example:

canarchy decode --file tests/fixtures/sample.candump --dbc tests/fixtures/sample.dbc --json

Notes:

  • --dbc accepts a local file path or a provider ref such as opendbc:<name>
  • --stdin reads JSONL frame events from standard input instead of a --file capture source
  • structured output includes a dbc_source object describing the provider-backed or local DBC resolution that was used
  • DBC signal.timestamp inherits the source-frame timestamp, including zero; unknown timestamps remain null without substituting wall-clock time, so signal-only streams retain observation timing
  • each DBC decoded_message and its child signal events carry the same zero-based payload.frame_index within one decode invocation; correlate using that index plus source/message/signal names rather than a decoded value

encode

Encode a DBC message into a frame payload.

canarchy encode --dbc <file> <message> <signal=value>...
                 [--crc-algorithm stellantis|sae-j1850|fca-giorgio]
                 [--json|--jsonl|--text]

Example:

canarchy encode --dbc tests/fixtures/sample.dbc EngineStatus1 CoolantTemp=55 OilTemp=65 Load=40 LampState=1 --json

Notes:

  • --dbc accepts a local file path or a provider ref such as opendbc:toyota_tnga_k_pt_generated
  • --crc-algorithm overrides checksum detection for DBC messages with an 8-bit CHECKSUM signal; when omitted, CANarchy attempts DBC-name detection and otherwise uses the default supported CRC behavior
  • explicitly supplied CHECKSUM=<value> signal assignments are preserved
  • structured output includes a dbc_source object describing the provider-backed or local DBC resolution that was used
  • message names resolve by exact DBC name, case/spacing-insensitive match, or SAE PGN label/name (e.g. EEC1 → the DBC message carrying PGN 61444); signal names resolve by exact DBC name, case/spacing-insensitive match, or the bundled SAE SPN name — so names displayed by decode/j1939 re-encode directly (e.g. encode EEC1 "Engine Speed=1200")
  • when a PGN label matches several messages (same PGN, different source addresses), the supplied signal names break the tie; a remaining ambiguity returns DBC_MESSAGE_NOT_FOUND listing the candidates
  • unsupplied signals default to the DBC initial value (else 0, clamped into range/choices) so single-signal encodes work; every default is reported under data.resolution.filled_signals and in a warning — review before transmitting (multiplexed messages are not auto-filled)
  • all non-exact resolutions are recorded under data.resolution (message.via, signal_aliases) and warned about; misspelled names get closest-match suggestions in the error hint
  • send --dbc applies the same resolution and defaulting, with a transmission-specific warning

plot

Plot decoded signal time-series from a capture to PNG, SVG, or HTML.

canarchy plot --file <capture> --dbc <path|provider:ref> --signal <name> [--signal <name> ...] \
    --out <path> [--format {png,svg,html}] [--offset <n>] [--max-frames <n>] [--seconds <s>] [--json|--jsonl|--text]

Example:

canarchy plot --file drive.candump --dbc truck.dbc --signal EngineSpeed --signal VehicleSpeed --out rpm.png --json

Notes:

  • requires the optional plotting extra: pip install canarchy[plot] (matplotlib for PNG/SVG, plotly for HTML); a missing dependency returns PLOT_DEPENDENCY_MISSING with the install hint
  • --dbc accepts a local database path or a provider:ref (e.g. opendbc:<name>), resolved like decode/encode; the envelope includes dbc_source describing the resolution, and a bad ref returns the standard DBC_* error
  • multiple --signal flags overlay signals; --format selects the renderer (default png)
  • the envelope reports the output file path plus signals_plotted and data_points
  • --offset, --max-frames, and --seconds bound the analysed window like the rest of the file-backed surface
  • structured errors: PLOT_DEPENDENCY_MISSING, PLOT_ERROR, UNSUPPORTED_OUTPUT_FORMAT

cannelloni decode

Decode a captured cannelloni CAN-over-UDP datagram payload into CAN frames.

canarchy cannelloni decode --file <payload> [--json|--jsonl|--text]

Notes:

  • reads one or more concatenated cannelloni datagrams (wire version 2) from a raw payload file and emits canonical frame events
  • passive and file-backed; supports classic CAN, extended, RTR, error, and CAN FD frames
  • structured errors: CANNELLONI_TRUNCATED, CANNELLONI_VERSION_UNSUPPORTED, CANNELLONI_INVALID_DLC, CANNELLONI_FILE_UNREADABLE

cannelloni send

Transmit a capture to a cannelloni endpoint as UDP datagrams.

canarchy cannelloni send <host:port> --file <capture> [--seq-no <n>] [--max-count <n>] \
    [--rate <hz>] [--ack-active] [--dry-run] [--offset <n>] [--max-frames <n>] [--seconds <s>] \
    [--json|--jsonl|--text]

Notes:

  • active-transmit path gated by the active-transmit safety design (--ack-active, YES confirmation, [safety].require_active_ack)
  • --dry-run plans the datagrams (returned as hex in data.datagrams) without opening a socket
  • --max-count bounds frames per datagram (default 64); --mtu bounds encoded bytes per datagram (default 1500, so a stock peer's MTU is not overrun by CAN FD frames; --mtu 0 disables it); --rate paces datagrams per second; --seq-no sets the starting cannelloni sequence number
  • CLI-only (not an MCP tool): active UDP egress to an arbitrary host
  • structured errors: CANNELLONI_INVALID_TARGET (exit 1), CANNELLONI_SEND_FAILED (exit 2)

web serve

Serve the read-only browser dashboard over HTTP + WebSocket.

canarchy web serve --file <capture> [--dbc <path|provider:ref>] [--bind <host:port>] \
    [--rate <multiplier>] [--loop] [--offset <n>] [--max-frames <n>] [--seconds <s>] \
    [--json|--jsonl|--text]

Example:

canarchy web serve --file tests/fixtures/j1939_heavy_vehicle.candump --dbc tests/fixtures/j1939_sample.dbc --json

Notes:

  • streams the capture as canonical envelope events (frame, j1939_pgn with bundled PGN/source-address annotation, decoded_message when --dbc is supplied, uds_transaction reassembled from the capture) to the bundled single-file SPA
  • the server is read-only: no active-transmit endpoints exist and non-GET requests return HTTP 405 with WEB_READ_ONLY
  • default bind is 127.0.0.1:8474; port 0 selects an ephemeral port and the startup envelope reports the resolved url
  • --rate scales timestamp pacing (0 disables it; gaps are capped at 1 s); --loop restarts the stream when the capture ends, otherwise a STREAM_COMPLETE alert closes it
  • structured errors: WEB_BIND_INVALID / WEB_BIND_FAILED (exit 1) and the standard capture-file transport errors (exit 2)
  • the command runs until interrupted and is not exposed as an MCP tool (long-running front end, like shell/tui)

dbc inspect

Inspect database, message, and signal metadata for a DBC file or provider ref.

canarchy dbc inspect <dbc> [--message <name>] [--signals-only] [--search <pattern>] [--layout] [--json|--jsonl|--text]

Examples:

canarchy dbc inspect tests/fixtures/sample.dbc --json
canarchy dbc inspect opendbc:toyota_tnga_k_pt_generated --message STEER_TORQUE_SENSOR --json
canarchy dbc inspect tests/fixtures/sample.dbc --message EngineStatus1 --layout --text

Notes:

  • <dbc> accepts a local file path or a provider ref such as opendbc:<name> or comma:<name>
  • the database file may be DBC (.dbc), ARXML (.arxml), KCD (.kcd), or SYM (.sym); the format is detected by suffix and data.database.format / data.dbc_source.kind report which loader was used
  • structured output includes dbc_source provenance alongside the inspection payload
  • --layout adds cantools-rendered per-message layout, signal_tree, and signal_choices strings; text output renders those diagrams directly, while JSON/JSONL keep them as fields on each message payload

dbc convert

Convert a loaded database to another cantools-supported serialization format (DBC, KCD, or SYM).

canarchy dbc convert <dbc> --to {dbc,kcd,sym} [--out <path>] [--json|--jsonl|--text]

Examples:

canarchy dbc convert tests/fixtures/sample.dbc --to kcd --out sample.kcd
canarchy dbc convert opendbc:toyota_tnga_k_pt_generated --to sym --json

Notes:

  • <dbc> accepts a local file path or a provider ref such as opendbc:<name>; the source may be any format the cantools runtime can load
  • serialization uses the cantools as_dbc_string / as_kcd_string / as_sym_string emitters — no hand-rolled writers
  • with --out, the converted database is written to the given path and the envelope reports out, target_format, message_count, and signal_count; without --out, the serialized content is returned in the envelope (and printed directly in --text mode)
  • structured errors cover unwritable output directories (DBC_CONVERT_WRITE_FAILED) and serialization failures where the target format cannot express a source feature (DBC_CONVERT_FAILED)

dbc generate-c

Generate C source and header files from a database using the cantools C source generator with pack/unpack structs and helpers.

canarchy dbc generate-c <dbc> [--out-dir <dir>] [--database-name <name>]
    [--no-floating-point-numbers] [--bit-fields] [--use-float] [--node <name>]
    [--use-round] [--json|--jsonl|--text]

Examples:

canarchy dbc generate-c tests/fixtures/sample.dbc --out-dir ./out --json
canarchy dbc generate-c opendbc:toyota_tnga_k_pt_generated --out-dir ./c_code --bit-fields --json

Notes:

  • <dbc> accepts a local file path or a provider ref such as opendbc:<name>; the source may be any format the cantools runtime can load
  • --out-dir specifies the output directory (default: current directory); it must already exist
  • --database-name sets the prefix used for all defines, data structures, and functions in the generated code (default: derived from the source filename stem)
  • four files are generated per database: .h header, .c source, _fuzzer.c fuzzer source, and _fuzzer.mk fuzzer makefile
  • the envelope returns out_dir, database_name, files (list of {path, kind, size_bytes}), and file_count
  • structured errors cover missing output directories (DBC_GENERATE_C_DIR_MISSING), write failures (DBC_GENERATE_C_WRITE_FAILED), and generation failures (DBC_GENERATE_C_FAILED)
  • MCP is not exposed — file generation is a developer action

dbc provider list

List registered DBC providers.

canarchy dbc provider list [--json|--jsonl|--text]

Search DBC catalogs across enabled providers.

canarchy dbc search <query> [--provider <name>] [--limit <n>] [--json|--jsonl|--text]

Example:

canarchy dbc search toyota --provider opendbc --limit 5 --json

dbc fetch

Fetch and cache a DBC file from a provider.

canarchy dbc fetch <ref> [--json|--jsonl|--text]

Example:

canarchy dbc fetch opendbc:toyota_tnga_k_pt_generated --json

dbc cache list

List cached provider manifests.

canarchy dbc cache list [--json|--jsonl|--text]

dbc cache prune

Remove stale cached provider snapshots while keeping the pinned commit.

canarchy dbc cache prune [--provider <name>] [--json|--jsonl|--text]

dbc cache refresh

Refresh a provider catalog from upstream.

canarchy dbc cache refresh [--provider <name>] [--json|--jsonl|--text]

Notes:

  • the default provider is opendbc
  • refreshing updates the cached catalog manifest; individual DBC files are fetched on demand or through dbc fetch
  • provider-backed decode, encode, and inspect commands return DBC_CACHE_MISS by default when the provider cache is cold; enabling [dbc.providers.opendbc].auto_refresh = true allows first-use refresh on resolution

skills provider list

List registered repository-backed skills providers.

canarchy skills provider list [--json|--jsonl|--text]

Search repository-backed skills catalogs by name, tag, or keyword.

canarchy skills search <query> [--provider <name>] [--limit <n>] [--json|--jsonl|--text]

Example:

canarchy skills search j1939 --provider github --json

skills fetch

Fetch and cache a repository-backed skill locally.

canarchy skills fetch <provider>:<skill> [--json|--jsonl|--text]

Example:

canarchy skills fetch github:j1939_compare_triage --json

skills cache list

List cached skills provider manifests.

canarchy skills cache list [--json|--jsonl|--text]

skills cache refresh

Refresh a skills provider catalog from upstream.

canarchy skills cache refresh [--provider <name>] [--json|--jsonl|--text]

Notes:

  • the first provider implementation is GitHub-backed and consumes .skill.yaml manifests that follow the CANarchy skill manifest schema
  • skills fetch returns both the cached manifest path and the cached skill entry path
  • skills provider/cache commands are mirrored by MCP tools for search/fetch/cache workflows, but skills themselves are workflow descriptors rather than MCP prompts or resources
  • agents should use skills as workflow descriptors: search, fetch, inspect compatibility/provenance, then run referenced CANarchy commands explicitly

plugins list

List registered Python entry-point plugins and built-in plugins.

canarchy plugins list [--json|--jsonl|--text]

Output includes each plugin's name, kind (processor, sink, or input), api_version, package version, source_distribution, entry_point_group, enabled, and configured_options fields.

plugins info

Show metadata and configured options for a registered plugin name.

canarchy plugins info <name> [--json|--jsonl|--text]

If the same name is registered in more than one plugin namespace, data.plugins contains each matching entry and data.match_count reports the count.

plugins enable / disable

Persist a plugin toggle in ~/.canarchy/config.toml under [plugins."<name>"].enabled.

canarchy plugins enable <name> [--json|--jsonl|--text]
canarchy plugins disable <name> [--json|--jsonl|--text]

Notes:

  • enable/disable requires the plugin to be discovered by the current environment; unknown names return PLUGIN_NOT_FOUND
  • plugins_list and plugins_info are mirrored by MCP tools; enable/disable is intentionally CLI-only because it writes user config

datasets provider list

List registered public CAN dataset providers.

canarchy datasets provider list [--json|--jsonl|--text]

Two providers are registered by default:

Provider Contents Network
catalog Metadata for well-known public research datasets. fetch records provenance; the data itself downloads from the publisher's host Required to obtain data
offline Synthetic datasets generated locally from protocol rules None

Provider resolution order

Providers are listed, and searched, in resolution order. That order decides which provider a bare ref (road, with no provider: prefix) resolves against; a prefixed ref (offline:can-basic) always goes straight to the named provider. The default is catalog first, so a bare ref prefers the real dataset of that name over synthetic data.

Override it with [datasets].search_order in ~/.canarchy/config.toml:

[datasets]
search_order = ["offline", "catalog"]

Rules:

  • Listed providers are searched first, in the order written. Duplicates collapse.
  • A registered provider that is enabled but not listed is appended after the listed ones rather than dropped — search_order states a preference, not an allow-list, so a partial list never makes offline: refs unresolvable.
  • Disabling a provider is a separate setting and always wins over listing it:
[datasets.providers.offline]
enabled = false
  • An unknown provider name fails loudly with DATASET_PROVIDER_NOT_FOUND (exit 1) rather than being ignored; a search_order that is not a list of names fails with DATASET_SEARCH_ORDER_INVALID (exit 1).

The effective order is inspectable — search_order in the JSON payload, an order index on each provider entry, and a Search order: line in text mode. When every provider is disabled, text mode says so explicitly ((none registered), Search order: (none), and the config key to re-enable one) rather than printing a bare heading; JSON returns empty providers and search_order lists:

canarchy datasets provider list --json
{
  "ok": true,
  "command": "datasets provider list",
  "data": {
    "providers": [
      {"name": "catalog", "registered": true, "order": 0},
      {"name": "offline", "registered": true, "order": 1}
    ],
    "search_order": ["catalog", "offline"]
  }
}

Every catalog download host (zenodo.org, figshare.com, huggingface.co, ocslab.hksecurity.net) is blocked under a typical sandboxed agent network policy. Where there is no egress, use offline refs instead: datasets fetch offline:<name> generates real data into the cache and returns its path, after which datasets convert, datasets stream, stats, j1939 summary and replay --file all work against a local file.

Offline datasets are synthetic. They carry real protocol structure but no vehicle behaviour, and are labelled as such in license, in a SYNTHETIC: description prefix, and by synthetic: true in the JSON machine fields. Use them to exercise tooling; do not report analysis of them as research findings.

Ref Source format Contents
offline:can-basic candump Periodic classic-CAN traffic with a rolling counter and checksum byte
offline:j1939-basic candump J1939 traffic with a BAM/TP sequence and a DM1 active fault
offline:can-intrusion hcrl-csv Attack-labelled rows, normal baseline plus injection bursts
offline:signal-decoded decoded-signal-csv Pre-decoded normalised per-ID signal columns

Search public CAN dataset provider catalogs by name, protocol, or keyword.

canarchy datasets search [query] [--provider <name>] [--limit <n>] [--verbose] [--json|--jsonl|--text]

datasets inspect

Show full metadata for a dataset ref.

canarchy datasets inspect <provider>:<dataset> [--json|--jsonl|--text]

Examples:

canarchy datasets search pivot
canarchy datasets inspect catalog:pivot-auto-datasets --json

Notes:

  • JSON datasets search and datasets inspect results include stable machine fields: ref, is_replayable, is_index, default_replay_file, download_url_available, and source_type
  • catalog:pivot-auto-datasets is a curated external source index, not a directly downloadable or replayable dataset
  • inspect linked source pages for per-dataset access terms, file formats, and conversion/replay suitability

datasets fetch

Record dataset provenance in the local cache. This does not download large dataset payloads.

canarchy datasets fetch <provider>:<dataset> [--json|--jsonl|--text]

Notes:

  • datasets fetch records provenance only for remote datasets — it does not download data. Use datasets download to retrieve the actual file, or datasets replay to stream it.
  • a provider that generates data locally (the offline provider) instead writes the real bytes into the cache; those fetches return data_is_local=true and a next_steps pointing at cache_path for capture-info, stats, replay --file, datasets convert, and datasets stream. datasets download and datasets replay do not apply and return DATASET_REPLAY_UNAVAILABLE.
  • normal (remote) dataset entries return data_is_local=false, download_instructions, plus a next_steps cross-link to datasets download/datasets replay
  • curated index entries return is_index=true and index_instructions; there is no single dataset payload to download
  • a cache-write failure returns DATASET_GENERATION_FAILED with exit code 2 (backend error), distinct from exit code 1 for a bad ref or unknown dataset

datasets download

Download a dataset's actual data file to disk (where the manifest exposes a direct URL). Reuses the same manifest resolution as datasets replay, but writes the native file verbatim rather than streaming decoded frames.

canarchy datasets download <provider>:<dataset> --out <path> [--file <name>] [--platform <p>] [--json|--jsonl|--text]
canarchy datasets download <https-url> --out <path> [--json|--jsonl|--text]

Notes:

  • --file selects a specific file from a multi-file dataset manifest (id or name); --platform filters dynamic manifests
  • reports out_path, bytes_written, source_format, and a next_steps hint for stats/datasets convert
  • a download/network failure returns a structured DATASET_DOWNLOAD_FAILED error; a non-replayable index returns DATASET_INDEX_NOT_REPLAYABLE
  • CLI-only operator action (writes bulk bytes to an arbitrary host path); not exposed as an MCP tool

datasets cache list

List cached dataset provider manifests and provenance records.

canarchy datasets cache list [--json|--jsonl|--text]

datasets cache refresh

Refresh the built-in dataset catalog manifest.

canarchy datasets cache refresh [--provider <name>] [--json|--jsonl|--text]

datasets convert

Convert a downloaded dataset file to a CANarchy-compatible capture format.

canarchy datasets convert <file> --source-format hcrl-csv|candump|comma-rlog|decoded-signal-csv --format candump|jsonl [--output <path>] [--json|--jsonl|--text]

datasets stream

Stream a downloaded dataset file to candump or JSONL without loading the full conversion into memory.

canarchy datasets stream <file> --source-format hcrl-csv|candump|comma-rlog|decoded-signal-csv --format candump|jsonl [--chunk-size <n>] [--max-frames <n>] [--provider-ref <ref>] [--output <path>] [--json]

Examples:

canarchy datasets stream sample.csv --source-format hcrl-csv --format jsonl --provider-ref catalog:hcrl-car-hacking
canarchy datasets stream sample.log --source-format candump --format jsonl --provider-ref catalog:candid
canarchy datasets stream rlog.zst --source-format comma-rlog --format jsonl --provider-ref catalog:comma-car-segments --max-frames 1000
canarchy datasets stream sample.csv --source-format hcrl-csv --format candump --output sample.candump
canarchy datasets stream sample.csv --source-format hcrl-csv --format jsonl --max-frames 1000
canarchy datasets stream sample.csv --source-format hcrl-csv --format jsonl --json

Notes:

  • datasets search defaults to a compact human-readable table with a TYPE column (INDEX for curated indexes, PLAY for replayable datasets); use --verbose for detailed result blocks with type labels, descriptions, source URLs, replay defaults, index notes, and access notes
  • without --json, stream records are written directly to stdout or --output
  • comma-rlog parses openpilot/comma rlog.zst CAN events when optional openpilot LogReader support is installed (uv pip install git+https://github.com/commaai/openpilot.git on Python 3.12.x); missing support returns COMMA_RLOG_SUPPORT_UNAVAILABLE
  • decoded-signal-csv ingests pre-decoded per-ID signal CSVs (e.g. SynCAN's Label,Time,ID,Signal1_of_ID,...): each row's ID token maps to a deterministic arbitration ID (0x-hex, plain decimal, or trailing integer like id10 -> 10, else a stable hash) and present normalized signal values are packed into payload bytes as big-endian uint16 (round(value * 0xFFFF), clamped); empty signal cells are skipped, and Time/Label are preserved (Label surfaces as payload.label in JSONL). Payload bytes are reconstructed, not captured verbatim — suitable for frame-level analysis (stats, re_*), not byte-exact ECU replay
  • JSONL stream records include payload.dataset.provider_ref, frame_offset, chunk_index, and chunk_position
  • --chunk-size controls JSONL provenance chunk metadata and does not bound emitted frames
  • --max-frames stops local dataset streaming after at most N emitted frames for candump and JSONL output
  • with --json, stdout contains the standard result envelope and reports frame_count, chunks, and max_frames
  • live-bus replay from dataset streams is not part of this command; use explicit replay workflows after writing a capture file

datasets replay

Stream a remote candump dataset file directly to stdout with replay timing. The source may be a direct candump download URL or a replayable dataset ref such as catalog:candid.

canarchy datasets replay <dataset-ref-or-url> [--file <id-or-name>] [--platform <name>] [--limit <n>] [--list-files] [--format candump|jsonl] [--rate <multiplier>] [--max-frames <n>] [--max-seconds <seconds>] [--dry-run] [--json]

Examples:

canarchy datasets replay catalog:candid --rate 1.0
canarchy datasets replay catalog:candid --format jsonl --rate 10 --max-frames 1000
canarchy datasets replay catalog:candid --format jsonl --rate 10 --max-seconds 30
canarchy datasets replay catalog:candid --list-files --json
canarchy datasets replay catalog:candid --file 2_indicator_CAN.log --rate 1000 --max-frames 10 --json
canarchy datasets replay https://ndownloader.figshare.com/files/54551156 --rate 1000 --max-frames 10
canarchy datasets replay catalog:candid --rate 1000 --max-frames 10 --json
canarchy datasets replay catalog:candid --dry-run --json
canarchy datasets replay catalog:comma-car-segments --platform TESLA_MODEL_3 --list-files --limit 20 --json
canarchy datasets replay catalog:comma-car-segments --platform TESLA_MODEL_3 --file 0 --format jsonl --max-frames 1000

Notes:

  • without --json, replayed frames are written directly to stdout as candump or JSONL records for piping
  • JSONL replay frame events include payload.dataset.provider_ref, source_url, replay_file, default_replay_file, frame_offset, source_format, and source_type
  • with --json, stdout contains a clean standard result envelope with replay metadata and no frame records
  • --list-files --json returns replay file entries with stable id, name, size_bytes, format, and source_url fields
  • --file accepts a replay file id or name; unknown files fail with DATASET_REPLAY_FILE_NOT_FOUND
  • catalog:comma-car-segments builds a dynamic replay manifest from HuggingFace database.json; use --platform to filter platforms such as TESLA_MODEL_3, and --limit to bound listed entries
  • commaCarSegments replay resolves HuggingFace LFS URLs only for active streaming; --dry-run and --list-files do not open rlog payload streams
  • Curated indexes that cannot be replayed return DATASET_INDEX_NOT_REPLAYABLE
  • Stdin pipeline: pipe datasets replay output into stats --file -, capture-info --file -, or filter --file - for analysis without temporary files
  • JSON summary output reports stop_reason, including eof, max_frames, max_seconds, broken_pipe, or interrupted
  • replay downloads incrementally from the remote HTTP response and does not require a complete local dataset file
  • --dry-run resolves replay source metadata without opening the remote stream
  • replaying a curated index entry fails with DATASET_INDEX_NOT_REPLAYABLE; other non-replayable datasets fail with DATASET_REPLAY_UNAVAILABLE
  • catalog:candid currently resolves to the CANdid 2_brakes_CAN.log Figshare file as its default replay source

session save

Save a named session with useful CLI context, recording provenance for the inputs it names: a SHA-256 hash, size, and modification time per capture/DBC file, the provider commit and ref when the DBC came from the provider cache, the effective configuration, and an environment snapshot.

canarchy session save <name> [--interface <name>] [--dbc <file>] [--capture <file>]
                             [--note <text>] [--artifact <file>]... [--json|--jsonl|--text]

Re-saving an existing name refreshes the context and inputs while keeping that session's creation timestamp, annotations, artifacts, and earlier invocations.

session load

Load a previously saved session and mark it active. Sessions saved before provenance recording load unchanged and report provenance_available: false with a SESSION_PROVENANCE_UNAVAILABLE warning; loading never rewrites them.

canarchy session load <name> [--json|--jsonl|--text]

session show

Show saved sessions and the active session, with per-session manifest version and input/artifact/annotation counts.

canarchy session show [--json|--jsonl|--text]

session verify

Re-hash every recorded input and artifact offline and report each as unchanged, changed, missing, or unverifiable, with the command to re-run per recorded invocation and a required_actions list. Exits 1 with SESSION_VERIFICATION_FAILED when anything changed or went missing. Reads files only — it never runs a recorded command or opens a transport.

canarchy session verify <name> [--root <dir>] [--json|--jsonl|--text]

--root resolves store-relative paths against another directory, which is how a relocated session is verified without its original absolute paths.

session annotate

Append a timestamped operator annotation, optionally targeting recorded input or artifact identifiers.

canarchy session annotate <name> --note <text> [--target <id>]... [--json|--jsonl|--text]

session attach

Record an analysis output as session evidence with its content hash, the command that produced it, and the inputs it was derived from. --embed stores the content inside the record so the result survives deletion of the original file.

canarchy session attach <name> --artifact <file> [--kind <kind>] [--command <text>]
                               [--derived-from <input-id>]... [--embed] [--json|--jsonl|--text]

session bundle

Write a portable bundle: the manifest plus copies of every available input and artifact, addressed by bundle-relative paths. A destination ending in .zip produces a zip archive; anything else produces a directory.

canarchy session bundle <name> --output <path> [--json|--jsonl|--text]

session import

Import a bundle into the local session store, copying its files in and rewriting the manifest to the imported copies.

canarchy session import <path> [--name <name>] [--json|--jsonl|--text]

shell

Run a single shell command through the shared parser, or start a minimal interactive shell loop.

canarchy shell [--command "capture can0 --text"] [--json|--jsonl|--text]

j1939 monitor

Inspect J1939 traffic and emit PGN-oriented structured events.

canarchy j1939 monitor [<interface>] [--pgn <id>] [--json|--jsonl|--text]

Example:

canarchy j1939 monitor --pgn 65262 --json
canarchy j1939 monitor can0 --pgn 65262 --json

Notes:

  • without an interface, this command uses an explicit sample/reference provider
  • with an interface, this command captures from the selected transport backend and filters to J1939 extended-ID traffic
  • j1939 decode, j1939 tp sessions, j1939 dm1, j1939 summary, j1939 inventory, j1939 compare, and j1939 map remain file-backed; j1939 pgn and j1939 spn accept an optional --file and otherwise perform a built-in reference lookup

j1939 decode

Decode a capture source into J1939 PGN observations.

canarchy j1939 decode --file <file> [--dbc <path|provider-ref>] [--json|--jsonl|--text]
canarchy j1939 decode --stdin [--dbc <path|provider-ref>] [--json|--jsonl|--text]

Notes:

  • --stdin reads JSONL frame events from standard input instead of a --file capture source
  • --dbc enriches J1939 results with DBC-backed decoded signal events when available

j1939 pgn

Inspect a specific PGN. With --file, reports matching events from the capture; without --file, returns the built-in reference definition (name, label, description, and the catalogued SPNs the PGN carries).

canarchy j1939 pgn <pgn> [--file <file>] [--dbc <path|provider-ref>] [--json|--jsonl|--text]

Example:

canarchy j1939 pgn 61444 --json
canarchy j1939 pgn 65262 --file tests/fixtures/sample.candump --json

j1939 spn

Inspect a specific SPN. With --file, runs the curated/DBC SPN decoder over recorded J1939 traffic; without --file, returns the built-in reference definition (name, owning PGN, units, resolution, offset, bit layout). An OEM SPN absent from the bundled catalog is resolved from a supplied/configured DBC.

canarchy j1939 spn <spn> [--file <file>] [--dbc <path|provider-ref>] [--json|--jsonl|--text]

Example:

canarchy j1939 spn 190 --json
canarchy j1939 spn 110 --file tests/fixtures/sample.candump --json

Notes:

  • curated metadata is built in for common SPNs
  • --dbc can expand coverage for SPNs exposed through DBC signal metadata
  • unsupported SPNs return a structured J1939_SPN_UNSUPPORTED error

j1939 tp sessions

Summarize J1939 transport-protocol sessions from a capture file. sessions is the default tp action, so j1939 tp --file <file> is equivalent to j1939 tp sessions --file <file>.

canarchy j1939 tp [sessions] <file> [--json|--jsonl|--text]
canarchy j1939 tp [sessions] --file <file> [--json|--jsonl|--text]

Notes:

  • the implementation handles BAM and RTS/CTS transport sessions with packet reassembly
  • j1939 tp --file <file> defaults to the sessions action; a bare positional path (j1939 tp <file>) must still be disambiguated via the explicit sessions/compare action or --file, since the next token is interpreted as the sub-action

j1939 dm1

Inspect DM1 fault traffic from direct J1939 frames and TP-reassembled payloads.

canarchy j1939 dm1 --file <file> [--dbc <path|provider-ref>] [--json|--jsonl|--text]

j1939 faults

Summarize active DM1 faults by ECU/source address, including lamp state and suspicious DTC markers.

canarchy j1939 faults --file <file> [--dbc <path|provider-ref>] [--json|--jsonl|--text]

j1939 inventory

Build a source-address inventory from a J1939 capture file, including top PGNs, component-identification strings, vehicle-identification strings, and DM1 presence.

canarchy j1939 inventory --file <file> [--json|--jsonl|--text]

Example:

canarchy j1939 inventory --file tests/fixtures/j1939_inventory.candump --json

Notes:

  • inventory rows are grouped by source address
  • printable TP payloads for component identification and vehicle identification are associated with the reporting source address when available
  • DM1 presence is summarised per source address so initial triage does not require a second command

j1939 compare

Compare two or more J1939 capture files and highlight common versus capture-unique PGNs, source-address changes, DM1 differences, and printable TP identification changes.

canarchy j1939 compare (<file> <file> [<file> ...] | --file <file> --file <file> ...) [--json|--jsonl|--text]

Example:

canarchy j1939 compare tests/fixtures/j1939_inventory.candump tests/fixtures/j1939_compare_shifted.candump --json

Notes:

  • this command requires at least two capture files
  • --max-frames, --seconds, and --offset apply independently to each compared capture file
  • DM1 differences are grouped by source address and surface active-fault or lamp-state changes when present
  • printable TP component-identification and vehicle-identification payloads are compared by source address and payload label

j1939 map

Build a passive network-topology map from a J1939 capture file: nodes (one per source address, carrying the SA name, decoded Address Claimed NAME fields when present, and component/vehicle identification strings) and edges (observed PGN flows from a source address to a destination, or to the broadcast/global address). The map is derived purely from captured frames — there is no active probing or address-claim solicitation.

canarchy j1939 map --file <file> [--json|--jsonl|--text]

Example:

canarchy j1939 map --file tests/fixtures/j1939_map.candump --json

Notes:

  • nodes reuse the j1939 inventory machinery, so identification strings and source-address names match between the two commands
  • the 64-bit NAME from an Address Claimed message (PGN 60928) is decoded into its constituent fields (manufacturer code, function, identity number, industry group, arbitrary-address-capable flag, and the instance fields) when address-claim traffic is present in the capture
  • edges aggregate repeated frames into a single per-(source, destination, PGN) flow with a frame count; PDU1 traffic addressed to the global address (0xFF) is reported as a broadcast, the same as PDU2 traffic
  • the structured nodes/edges output is suitable for graphing and diffing

tui

Start the full-screen TUI.

canarchy tui

Notes:

  • a full-screen Textual application that requires an interactive terminal; in a non-TTY context it emits the canonical error envelope (TUI_REQUIRES_TTY, honouring --json/--jsonl) and exits non-zero
  • active-transmit commands (e.g. send, generate, uds scan) are refused from the TUI command entry — their YES confirmation prompt cannot be answered inside the full-screen app, so run them from the CLI
  • responsive workspaces: Traffic, Signals, J1939 (summary ribbon + recent table), UDS, and Findings; the source/capture status band, compact activity log, and command entry remain visible
  • Traffic also folds DBC decoded_message events with embedded frames into its identifier summary and chronological log, correlating child signal events for inspection
  • Alt+1–Alt+5 switch workspaces, v switches Traffic between its per-bus typed identifier summary and chronological event log, F4 freezes inspection or returns live, F3 expands activity, and Enter inspects a selected row on narrow terminals; wide terminals show a contextual inspector
  • /capture <iface> streams the bus live in the background; /stop (or x) ends it. /stop takes no arguments — anything after it is rejected in the alerts log and the capture keeps running. /capture takes exactly one interface — an empty or extra argument is rejected in the alerts log and leaves any running capture alone; use the full capture command when you need flags
  • /clear (or c) is the only slash command that discards pane data; /help and the other read-only hotkeys never clear rows
  • /capture and /stop tokenise their arguments: an unmatched quote or a dangling backslash is reported in the alerts log and the TUI stays running. /filter and /sort take raw text instead, so a filter needle may contain a quote character; they validate their pane argument and leave state unchanged when it is not recognised
  • panes are interactive: /filter <pane> [text], /sort <pane> [column], arrow-key row navigation, [/] to resize the backlog, space to pause the feed. Traffic also accepts canonical typed id==, pgn==, and sa== filters; unknown sort fields and invalid typed filters are reported without replacing the current state
  • command entry runs existing CANarchy commands through the shared parser and result path; slash hotkeys (/save, /load, /dbc, /doctor, /config, …) expand to those commands
  • non-event answers, errors, help, and version output appear in a scrollable, selectable result view rather than disappearing behind the full-screen interface. F2 switches between the result and the live panes; Esc returns to the panes. Event rows remain retained while the result is open
  • nested interactive front ends like shell or tui are rejected from TUI command entry (TUI_COMMAND_UNSUPPORTED)

uds scan

Inspect representative UDS responder discovery transactions.

canarchy uds scan <interface | doip://host:port?logical_address=0x0E80> [--ack-active] [--json|--jsonl|--text]

Notes:

  • with the python-can backend, this command sends a single-frame functional DiagnosticSessionControl request and summarizes captured UDS responses after ISO-TP reassembly when needed
  • with the scaffold backend, this command emits explicit sample/reference UDS transaction data
  • a doip://<host>:<port>?logical_address=0x0E80 target routes the scan over DoIP (Diagnostic over IP, ISO 13400-2): the command opens a TCP connection, performs routing activation, and probes the default / programming / extended diagnostic sessions, emitting the same uds_transaction events with transport: doip in the envelope. Optional query parameters: source_address (tester address, default 0x0E00), activation_type (default 0x00), timeout (seconds, default 2.0); port defaults to 13400
  • DoIP targets are an active network egress and are gated by the active-transmit safety model; structured errors include DOIP_INVALID_TARGET (exit 1), DOIP_CONNECTION_FAILED / DOIP_TIMEOUT / DOIP_ROUTING_ACTIVATION_DENIED / DOIP_DIAGNOSTIC_NACK / DOIP_PROTOCOL_ERROR (exit 2)
  • --ack-active requests an interactive YES confirmation before the diagnostic request is sent
  • if a segmented response is truncated or arrives out of order, the emitted uds_transaction event keeps the partial response_data and sets complete to false

uds trace

Inspect representative UDS request and response transactions.

canarchy uds trace <interface | doip://host:port?logical_address=0x0E80> [--ack-active] [--json|--jsonl|--text]

Notes:

  • with the python-can backend, this command captures raw CAN frames and infers UDS request/response transactions from common diagnostic IDs, including ISO-TP multi-frame responses
  • with the scaffold backend, this command emits explicit sample/reference UDS transaction data
  • a doip:// target routes the trace over DoIP: the command performs routing activation and a DiagnosticSessionControl + TesterPresent exchange, emitting the transactions with transport: doip. Because DoIP is connection-oriented, this is an active exchange (not a passive sniff) and is gated by the active-transmit safety model; the same DoIP query parameters and error codes as uds scan apply
  • flow-control frames are used only for reassembly and are not emitted as transactions
  • if a segmented response is truncated or arrives out of order, the emitted uds_transaction event keeps the partial response_data and sets complete to false

uds services

Inspect the built-in UDS service catalog, or actively probe which services an ECU supports.

canarchy uds services [<interface>] [--request-id 0x7E0] [--response-id 0x7E8] \
    [--probe-start 0x00 --probe-end 0xFF] [--max-requests N] [--timeout S] \
    [--dry-run] [--ack-active] [--json|--jsonl|--text]

Notes:

  • without an interface this is a reference command (mode: reference): output includes service identifier, positive-response identifier, category, and subfunction expectations
  • with an interface this becomes an active probe (mode: active, gated by the active-transmit safety model): each candidate service id is sent once to --request-id, and a service is reported supported when it answers positively or with any negative response code other than ServiceNotSupported / ServiceNotSupportedInActiveSession
  • --probe-start/--probe-end probe a raw service-id range instead of the catalog; --max-requests caps the probe count

uds subservices

Enumerate which subfunctions of a UDS service an ECU supports.

canarchy uds subservices <interface> --service 0x19 [--sub-start 0x00] [--sub-end 0xFF] \
    [--request-id 0x7E0] [--response-id 0x7E8] [--timeout S] [--dry-run] [--ack-active] [--json|--jsonl|--text]

uds ecu-reset / uds tester-present

Send a single ECUReset (0x11) or TesterPresent (0x3E) request.

canarchy uds ecu-reset <interface> [--reset-type 0x01] [--ack-active] [--dry-run] [--json|--jsonl|--text]
canarchy uds tester-present <interface> [--suppress] [--ack-active] [--dry-run] [--json|--jsonl|--text]

uds security-seed

Collect SecurityAccess (0x27) seeds for an explicit session and level.

canarchy uds security-seed <interface> [--level 0x01] [--session 0x03] [--count N] \
    [--max-duration S] [--ack-active] [--dry-run] [--json|--jsonl|--text]

Notes:

  • --level must be odd (the requestSeed subfunction); --session optionally enters a diagnostic session first
  • output reports collected, distinct_seeds, and the per-request seed bytes

uds dump-dids

Read a range of DataIdentifiers via ReadDataByIdentifier (0x22).

canarchy uds dump-dids <interface> [--did-start 0xF180] [--did-end 0xF1FF] [--limit 256] \
    [--max-duration S] [--ack-active] [--dry-run] [--json|--jsonl|--text]

uds read-memory

Read a bounded memory range via ReadMemoryByAddress (0x23).

canarchy uds read-memory <interface> --address 0x080000 --size N [--chunk-size 4] \
    [--address-bytes N] [--size-bytes N] [--output PATH] [--ack-active] [--dry-run] [--json|--jsonl|--text]

Notes:

  • the request is chunked by --chunk-size; the total size is bounded (max 65536 bytes)
  • --output writes the reassembled memory bytes to a file when any bytes were read; provenance (address, size, chunk_size, request/response ids) is in the result data

uds auto

Bounded zero-knowledge active diagnostic reconnaissance: discover responders, probe services, optionally probe a bounded DID range.

canarchy uds auto <interface> [--request-start 0x7E0] [--request-end 0x7E7] [--no-services] \
    [--probe-dids --did-start 0xF190 --did-end 0xF19F --did-limit 16] [--response-id ID] \
    [--max-duration S] [--ack-active] [--dry-run] [--json|--jsonl|--text]

Notes:

  • discovery sends a DiagnosticSessionControl request to each id in [--request-start, --request-end] and notes responders; --response-id is auto (any responder id) unless pinned
  • per responder it enumerates supported services (unless --no-services) and, with --probe-dids, reads a bounded DID range; the result reports complete for the scan budget
  • all uds active workflows (everything except the reference uds services catalog) are CLI-only operator actions and are not exposed as MCP tools

xcp scan

Discover XCP responders by transmitting an XCP CONNECT command.

canarchy xcp scan <interface> [--request-id 0x3E0] [--response-id 0x3E1] [--ack-active] [--dry-run] [--json|--jsonl|--text]

Notes:

  • XCP-on-CAN: sends a single CONNECT (FF 00) on --request-id and reports each command-response object on --response-id as an xcp_transaction event; a CONNECT positive response is parsed into resources, max-CTO, max-DTO, and protocol/transport versions
  • with the scaffold backend, this command emits sample/reference XCP transaction data
  • this is an active command honouring the active-transmit safety model; --ack-active requests an interactive YES confirmation before the CONNECT is sent; --dry-run plans the CONNECT frame (reported as planned_frame, mode: dry_run) without opening the transport or transmitting
  • --request-id / --response-id accept decimal or 0x hex CAN ids (defaults 0x3E0 / 0x3E1; an extended 29-bit request id is transmitted as an extended frame); a malformed id returns XCP_INVALID_ID
  • the xcp_scan MCP tool is gated like other active-transmit tools: mandatory ack_active=true with dry_run defaulting to true

xcp info

Connect to an XCP slave and report its basic capabilities.

canarchy xcp info <interface> [--request-id 0x3E0] [--response-id 0x3E1] [--timeout S] [--ack-active] [--dry-run] [--json|--jsonl|--text]

Notes:

  • sends CONNECT, then the optional GET_STATUS, GET_COMM_MODE_INFO, and GET_ID commands; the capabilities block reports the parsed CONNECT info (resources, max-CTO/DTO, byte order, versions) plus session status, comm-mode info, and identification mode/length
  • optional commands the slave does not implement are reported per-command as status: unsupported rather than failing the whole command
  • active command honouring the active-transmit safety model; --dry-run plans the four commands without transmitting and needs no interface
  • a silent slave returns XCP_NO_RESPONSE and a CONNECT rejection returns XCP_ERROR_RESPONSE (exit 2)

xcp dump

Upload a bounded XCP memory range.

canarchy xcp dump <interface> --address 0x08000000 --size N [--chunk-size 4] [--address-extension 0x00] \
    [--short-upload] [--output PATH] [--timeout S] [--ack-active] [--dry-run] [--json|--jsonl|--text]

Notes:

  • CONNECT, then uploads the range in --chunk-size chunks (1–7 bytes, bounded by the slave's MAX_CTO-1) via SET_MTA + UPLOAD, or SHORT_UPLOAD with --short-upload
  • the total size is bounded (max 65536 bytes); --output writes the assembled bytes when any were read; the envelope reports bytes_read, complete, the per-chunk records, and the assembled memory hex
  • address byte order follows the slave's CONNECT comm-mode-basic byte order
  • bounds errors (XCP_INVALID_VALUE, XCP_DUMP_TOO_LARGE, XCP_INVALID_CHUNK_SIZE, XCP_CHUNK_EXCEEDS_MAX_CTO) exit 1; XCP_NO_RESPONSE / XCP_ERROR_RESPONSE exit 2
  • xcp info and xcp dump are CLI-only operator actions and are not exposed as MCP tools

xcp trace

Pair XCP command and response transactions from bus traffic.

canarchy xcp trace <interface> [--request-id 0x3E0] [--response-id 0x3E1] [--json|--jsonl|--text]

Notes:

  • passive: pairs each command CTO on --request-id with the following response CTO on --response-id, naming the command and surfacing positive/error status (error codes resolve to ASAM names)
  • with the scaffold backend, this command emits sample/reference XCP transaction data

xcp read

Surface raw DAQ measurement (DTO) payloads from a short capture.

canarchy xcp read <interface> [--response-id 0x3E1] [--json|--jsonl|--text]

Notes:

  • passive: emits an xcp_measurement event (packet identifier plus raw bytes) for each DAQ DTO on --response-id; command-response objects (PID ≥ 0xFC) are skipped
  • signal-level decoding of DAQ payloads requires the slave's A2L description and is out of scope; raw ODT bytes are reported

xcp commands

Inspect the built-in XCP command catalog.

canarchy xcp commands [--json|--jsonl|--text]

Notes:

  • this is a reference command and does not require an interface
  • output includes the command code, name, and category (standard / calibration / daq / programming)

doip discovery

Discover reachable DoIP entities via a UDP vehicle-identification broadcast.

canarchy doip discovery [host] [--port 13400] [--timeout 2.0] [--ack-active] [--dry-run] [--json|--jsonl|--text]

Notes:

  • broadcasts a DoIP VehicleIdentificationRequest (default host 255.255.255.255) and reports each responding entity's VIN, logical address, EID, and GID
  • active network egress honouring the active-transmit safety model; --dry-run plans the broadcast without transmitting
  • a send failure returns DOIP_CONNECTION_FAILED (exit 2)

doip services / ecu-reset / tester-present / security-seed / dump-dids

Active UDS diagnostic workflows over a DoIP session, addressing the ECU by logical address.

canarchy doip services       <doip-uri> [--ack-active] [--dry-run] [--json|--jsonl|--text]
canarchy doip ecu-reset      <doip-uri> [--reset-type 0x01] [--ack-active] [--dry-run] ...
canarchy doip tester-present <doip-uri> [--suppress] [--ack-active] [--dry-run] ...
canarchy doip security-seed  <doip-uri> [--level 0x01] [--session 0x03] [--count N] [--ack-active] [--dry-run] ...
canarchy doip dump-dids      <doip-uri> [--did-start 0xF180] [--did-end 0xF1FF] [--limit N] [--ack-active] [--dry-run] ...

Where <doip-uri> is doip://<host>:<port>?logical_address=0x0E80 (same query parameters as uds scan over DoIP).

Notes:

  • each workflow activates routing, then runs the relevant UDS requests over the DoIP session, emitting uds_transaction events with negative-response decoding plus per-request status
  • services reports which UDS services the ECU supports; security-seed requires an odd --level; dump-dids reads a bounded DID range
  • all doip commands honour the active-transmit safety model and support --dry-run request plans; bounds/validation errors (DOIP_INVALID_VALUE, DOIP_INVALID_SECURITY_LEVEL, DOIP_INVALID_DID_RANGE) exit 1 and DoIP transport/protocol errors exit 2
  • the doip command group is CLI-only and is not exposed as MCP tools (active network egress to an arbitrary host)

j1587 decode

Decode a J1708 capture file into J1587 PID parameters.

canarchy j1587 decode --file <path> [--offset N] [--max-frames N] [--seconds N] [--json|--jsonl|--text]
canarchy j1587 decode --file tests/fixtures/j1708_sample.j1708 --json

Notes:

  • each line of the capture file must read (timestamp) j1708 <hex>, where <hex> is the full raw message (source MID, PID-framed parameters, and a trailing checksum byte)
  • emits one j1587_parameter event per parameter, with mid, pid, raw, name, value, units, checksum_valid, and timestamp; PIDs are resolved against the bundled resources/j1587/pids.json catalog (override via CANARCHY_J1587_PID_OVERRIDES or ~/.canarchy/j1587_pids.json)
  • an all-ones raw value (the J1587 "data not available" sentinel) resolves value to null while keeping name/units
  • data reports mode: "passive", file, message_count, parameter_count, and checksum_failures
  • --offset / --max-frames / --seconds apply to the message stream the same way they do for j1939 decode
  • a missing --file returns J1587_SOURCE_UNAVAILABLE; a line that does not match the expected format, has an odd number of hex digits, or fails J1708 framing returns J1587_SOURCE_INVALID (exit code 1)

j1587 pids

Inspect the built-in J1587 PID catalog.

canarchy j1587 pids [--json|--jsonl|--text]

Notes:

  • this is a reference command and does not require a capture file
  • output includes each PID's name, data length, resolution, offset, units, and byte order

j2497 decode

Decode a J2497 (PLC4TRUCKS trailer power-line) capture file into frames.

canarchy j2497 decode --file <path> [--offset N] [--max-frames N] [--seconds N] [--json|--jsonl|--text]
canarchy j2497 decode --file tests/fixtures/j2497_sample.j2497 --json

Notes:

  • each line of the capture file must read (timestamp) j2497 <hex>, where <hex> is the full raw frame (source MID, message data, and a trailing checksum byte)
  • emits one j2497_message event per frame, with mid, name, data, checksum_valid, and timestamp; MIDs are resolved against the bundled resources/j2497/mids.json catalog (override via CANARCHY_J2497_MID_OVERRIDES or ~/.canarchy/j2497_mids.json)
  • J2497 reuses the J1708/J1587 frame format; the data bytes follow the J1587 PID framing rules, so feed the same byte format to j1587 decode for PID-level resolution
  • data reports mode: "passive", file, frame_count, and checksum_failures
  • --offset / --max-frames / --seconds apply to the frame stream the same way they do for j1939 decode
  • live J2497 / power-line access requires a power-line carrier modem and external hardware and is not provided; this command is decode-only over captured frames
  • a missing --file returns J2497_SOURCE_UNAVAILABLE; a line that does not match the expected format, has an odd number of hex digits, or is too short to be a frame returns J2497_SOURCE_INVALID (exit code 1)

j2497 mids

Inspect the built-in J2497/J1587 MID catalog.

canarchy j2497 mids [--json|--jsonl|--text]

Notes:

  • this is a reference command and does not require a capture file
  • output includes each MID's ECU name (trailer ABS controllers and related units)

re counters

Rank likely counter fields from recorded CAN traffic.

canarchy re counters (<file> | --file <file>) [--top <n>] [--json|--jsonl|--text]

Notes:

  • this command is passive and file-backed
  • the current implementation inspects nibble- and byte-sized candidate fields on recorded arbitration IDs
  • candidates are ranked by monotonicity evidence and explicit rollover detection
  • J1939 transport-protocol IDs (TP.CM / TP.DT / ETP.CM / ETP.DT) are excluded — their sequence numbers are protocol plumbing, not application counters — and reported in metadata as excluded_transport_ids
  • J1939 candidates carry pgn, pgn_label, source_address, and source_address_name; every candidate carries arbitration_id_hex
  • --top caps the returned candidates array (default 20; 0 for all); candidate_count reports the full total and returned_count the number returned

re signals

Rank likely signal fields from recorded CAN traffic.

canarchy re signals (<file> | --file <file>) [--top <n>] [--json|--jsonl|--text]

Notes:

  • this command is passive and file-backed
  • the current implementation inspects nibble-aligned 4-bit fields, byte-aligned 8-bit fields, and word-aligned 16-bit fields
  • candidates are ranked by change-rate preference, observed range, and value diversity
  • J1939 transport-protocol IDs (TP.CM / TP.DT / ETP.CM / ETP.DT) are excluded from signal inference and reported under excluded_transport_ids
  • J1939 candidates carry pgn, pgn_label, source_address, and source_address_name; every candidate carries arbitration_id_hex
  • arbitration IDs with fewer than 5 frames are omitted from the candidate list and reported in low_sample_ids
  • --top caps the returned candidates array (default 20; 0 for all); candidate_count reports the full total and returned_count the number returned

re correlate

Correlate candidate bit fields against a timestamped reference series.

canarchy re correlate (<file> | --file <file>) --reference <ref.json|ref.jsonl> [--json|--jsonl|--text]

Notes:

  • this command is passive and file-backed
  • reference files may be JSON arrays, named JSON objects with name and samples, or JSONL sample streams
  • each reference sample must include numeric timestamp and value fields
  • candidates report pearson_r, spearman_r, sample_count, and lag_ms, and are ranked by absolute Pearson correlation

re anomalies

Flag inter-frame-timing outliers and unexpected/dropped arbitration IDs.

canarchy re anomalies (<file> | --file <file>) [--baseline <ref>] [--dbc <ref>] [--z-threshold <z>] \
    [--cv-max <cv>] [--min-samples <n>] [--entropy-drop <r>] [--rate-drop <r>] [--top <n>] \
    [--offset <n>] [--max-frames <n>] [--seconds <s>] [--json|--jsonl|--text]

Notes:

  • this command is passive and file-backed; it honors the standard --offset, --max-frames, and --seconds window flags
  • with --baseline, per-ID timing statistics and the expected ID set are learned from the reference capture and the input is scored against them; without it, each ID is scored against its own statistics (self-consistency), ID-presence anomalies are not emitted, and a warning nudges the operator toward supplying a baseline
  • anomalies carry arbitration_id, kind (timing / unknown-id / dropped-id / rate-drop / rate-spike / entropy-collapse), score, z_score, z_score_capped, sample_count, timestamp, and a rationale, ranked by score; J1939 candidates additionally carry pgn, pgn_label, source_address, and source_address_name
  • against a --baseline, IDs present in both captures are additionally checked for two attack classes that pure timing analysis misses: a rate-drop / rate-spike when an ID's time-normalised frame rate falls to --rate-drop of (default 0.5; suppression) or rises to its reciprocal above (injection) the baseline rate, and an entropy-collapse when an ID's mean per-byte payload entropy falls to --entropy-drop of (default 0.5) a baseline that itself carried meaningful entropy (plateau / frozen-value attacks)
  • --rate-drop and --entropy-drop must each be strictly between 0 and 1 (an out-of-range ratio would make the corresponding check fire on unchanged IDs or never fire at all); out-of-range values are rejected with INVALID_RATE_DROP / INVALID_ENTROPY_DROP
  • only IDs judged cyclic are timing-checked, so event-based and event-periodic messages are not falsely flagged. Classification is authoritative from the database when --dbc is supplied (a message's cycle_time / send type decides cyclic vs event); otherwise a robust coefficient of variation (scaled median-absolute-deviation over the median inter-frame gap) is compared against --cv-max (default 0.5)
  • timing statistics use the median and MAD rather than mean and standard deviation, so a minority of outlier gaps cannot inflate the spread and mask themselves
  • a cyclic-looking ID needs at least --min-samples inter-frame gaps before its timing is scored (default 10 without a baseline, 3 with one); sparser IDs are listed under low_rate_ids with classification source low-sample instead of being ranked, and reported z-scores are capped at ±100σ
  • --top caps the ranked candidates array (default 20; 0 for all) for agent-friendly output; candidate_count always reports the full total and returned_count the number returned
  • the payload also reports mode, timing_source (dbc / observed), min_samples, entropy_drop, rate_drop, cyclic_ids, event_ids (timing skipped), low_rate_ids, and a per-ID classifications list

re corpus

Cross-capture corpus analysis: per-ID coverage matrix, cycle-time drift, and signal stability across multiple captures.

canarchy re corpus (<file> ... | --file <file> ...) [--corpus-glob <pattern>] \
    [--offset <n>] [--max-frames <n>] [--seconds <s>] [--json|--jsonl|--text]

Notes:

  • this command is passive and file-backed; accepts two or more captures positionally, via repeatable --file, or expanded from --corpus-glob
  • reports per-ID coverage (frame counts per capture, presence), cycle_time_drift (cross-capture mean-gap stddev and drift ratio), and signal_stability (per-byte coefficient of variation), plus a summary of unique/stable/drifting/new IDs
  • J1939 ids are annotated with pgn, pgn_label, and source_address_name; every row carries arbitration_id_hex
  • --offset, --max-frames, and --seconds bound each capture independently

re entropy

Rank arbitration IDs and byte positions by Shannon entropy over recorded CAN traffic.

canarchy re entropy (<file> | --file <file>) [--top <n>] [--json|--jsonl|--text]

Notes:

  • this command is passive and file-backed
  • JSON output includes one candidate per arbitration ID plus a per-byte entropy breakdown inside each candidate
  • IDs with fewer than 10 observed frames are retained and marked with low_sample: true
  • J1939 transport-protocol IDs are retained but labeled with j1939_transport: true and a rationale note, so TP framing is not mistaken for an application signal
  • J1939 candidates carry pgn, pgn_label, source_address, and source_address_name; every candidate carries arbitration_id_hex
  • --top caps the returned candidates array (default 20; 0 for all); candidate_count reports the full total and returned_count the number returned

re match-dbc

Rank candidate DBC files against a capture using provider-backed catalog metadata.

canarchy re match-dbc (<capture> | --file <capture>) [--provider <name>] [--limit <n>] [--json|--jsonl|--text]

Notes:

  • this command is passive and file-backed
  • candidates are scored by frequency-weighted arbitration-ID coverage against the capture
  • the default provider is opendbc

re shortlist-dbc

Rank candidate DBC files against a capture after pre-filtering by vehicle make.

canarchy re shortlist-dbc (<capture> | --file <capture>) --make <brand> [--provider <name>] [--limit <n>] [--json|--jsonl|--text]

Notes:

  • this command is passive and file-backed
  • --make narrows provider-catalog candidates before scoring them against the capture
  • the default provider is opendbc

re suggest

Propose names for ranked signal candidates.

canarchy re suggest (<file> | --file <file>) [--reference-dbc <ref>] [--limit <n>] \
    [--llm <provider> [--llm-model <model>] [--yes]] [--json|--jsonl|--text]

Notes:

  • passive and file-backed: reuses re signals to rank candidates, then attaches suggestions (each with a source of dbc / spn / pgn / heuristic / llm and a confidence), reporting the top as suggested_name / suggested_source
  • Reference-DBC matching in re suggest uses exact physical-bit overlap for Intel and Motorola signals; sharing a byte alone is insufficient. Confidence remains heuristic, and corrected overlap can change suggestion inclusion and ranking without changing output fields.
  • heuristics combine reference-DBC overlap (--reference-dbc, a path or provider ref), bit-range overlap with the bundled J1939 SPN catalog, the PGN name as a coarse fallback, and a plain-English template from the candidate's change behaviour — all fully offline
  • --llm <provider> (off by default; only anthropic is supported) enriches names via an external LLM. It requires explicit confirmation (--yes, or a YES reply, or CANARCHY_LLM_NONINTERACTIVE=1), sends only candidate metadata — never payload bytes — and records external_enrichment plus an EXTERNAL_SERVICE_CALLED warning. Declining returns LLM_CONFIRMATION_DECLINED; an unknown provider returns LLM_PROVIDER_UNSUPPORTED; a missing key returns LLM_PROVIDER_UNAVAILABLE
  • the re_suggest MCP tool exposes the heuristic path only; the --llm enrichment is CLI-only

config show

Inspect the effective transport configuration and the source of each setting.

canarchy config show [--json|--jsonl|--text]

The payload includes both interface (the python-can backend type) and default_interface (the optional CAN channel fallback for commands that omit their interface argument).

doctor

Run local environment health checks and return the canonical envelope. Each check has a name, status (ok, warn, or fail), detail, and an optional hint for non-ok results.

canarchy doctor [--json|--jsonl|--text]

Covered checks:

  • python_version — Python is at least 3.12.
  • python_can — python-can is importable in the active environment.
  • transport_backend — the effective transport backend resolves to a known backend.
  • python_can_interface_dependency — when the effective python-can interface is a known vendor backend such as pcan, vector, or kvaser, the corresponding python-can interface module is importable. This is an offline import check only; it does not open hardware.
  • config_file — ~/.canarchy/config.toml parses cleanly when present.
  • cache_dirs — DBC, dataset, and skills caches are writable.
  • opendbc_cache — opendbc DBC cache is populated; warns if it needs dbc cache refresh.
  • mcp_server — the MCP stdio server is constructable.
  • version_consistency — the installed package version matches src/canarchy/__init__.py.

The command also runs against the MCP server as the doctor tool. No network or live bus access is required.

completion

Emit a shell completion script for the given shell. The script is written to stdout — not wrapped in the canonical envelope, because the output is meant to be sourced.

canarchy completion {bash,zsh,fish}

Install snippets:

  • bash — eval "$(canarchy completion bash)" in ~/.bashrc, or copy the output into ~/.bash_completion.d/canarchy.
  • zsh — eval "$(canarchy completion zsh)" in ~/.zshrc, or save the output to a directory on $fpath such as ~/.zsh/completions/_canarchy and run compinit.
  • fish — canarchy completion fish | source from ~/.config/fish/config.fish, or save to ~/.config/fish/completions/canarchy.fish.

Supplying an unsupported shell name returns the standard INVALID_ARGUMENTS structured error.

Global flags

The following flags are accepted before any subcommand (place them between canarchy and the subcommand name):

  • --log-level {debug,info,warn,error} — stderr log verbosity; defaults to warn. Log records never contaminate machine-readable stdout (--json, --jsonl, --text).
  • --quiet — suppress every level below ERROR. Useful in pipelines where only structured errors should reach stderr.

fuzz

Active-transmit fuzzing, gated by the controls in docs/design/active-transmit-safety.md. Three subcommands, all built on the pure-function mutation engine in src/canarchy/fuzzing.py. Every emitted event carries a stable run_id (UUID) so post-mortem analysis can match output to the invocation that produced it.

--dry-run is the safe planning path: events are emitted as JSONL with payload.frame.dry_run = true, no transport is opened, and the --ack-active confirmation prompt is skipped. Without --dry-run, the existing active-transmit safety gate (--ack-active plus optional config-driven prompt) applies before any frame is transmitted via LocalTransport.send.

canarchy fuzz payload <interface> --id <hex> --strategy {bitflip,random,boundary}
                                  [--data <hex>] [--dlc <n>] [--max <n>]
                                  [--rate <hz>] [--seed <int>] [--extended]
                                  [--repair-crc] [--crc-algorithm <name>] [--crc-address <id>]
                                  [--dry-run] [--run-id <uuid>] [--ack-active]
canarchy fuzz replay --file <capture> --strategy {timing,payload-bitflip}
                      [--interface <iface>] [--max <n>] [--rate <hz>] [--seed <int>]
                      [--repair-crc] [--crc-algorithm <name>] [--crc-address <id>]
                      [--dry-run] [--run-id <uuid>] [--ack-active]
canarchy fuzz arbitration-id <interface> --range <start>:<end> [--step <n>]
                               [--data <hex>] [--rate <hz>] [--extended]
                               [--repair-crc] [--crc-algorithm <name>] [--crc-address <id>]
                               [--dry-run] [--run-id <uuid>] [--ack-active]

--repair-crc recomputes the final payload byte after mutation. --crc-algorithm accepts stellantis, sae-j1850, or fca-giorgio; if omitted, fuzz repair uses stellantis. --crc-address supplies the arbitration ID used by algorithms that include the message address; when omitted, each generated frame's arbitration ID is used.

Strategies and the engine they map to are documented in the active-transmit safety design. The following follow-up controls from that spec are tracked separately and will land in subsequent PRs: configurable rate-cap ceiling ([safety.rate_cap] in ~/.canarchy/config.toml), TOML target allowlist (--targets), explicit KILL_SWITCH_TRIGGERED alert on SIGINT, MCP ack_active=true enforcement (#312).

fuzz guided

Response-feedback coverage-guided fuzzing against an ECU target.

canarchy fuzz guided <interface> --id <arb-id> [--signals nrc,pos,dm1,timing,silence]
                     [--corpus <dir>] [--findings-dir <root>] [--seed-data <hex>] [--max-iterations <n>]
                     [--max-seconds <s>] [--max-corpus <n>] [--rate <hz>] [--seed <int>]
                     [--extended] [--ack-active] [--dry-run] [--json|--jsonl|--text]

Notes:

  • active-transmit: each iteration sends a mutated payload (via the canarchy.fuzzing havoc/splice mutators) on --id and observes the target's response. Novelty is scored from observed responses — UDS NRCs, UDS positive responses, DM1 fault emergence, response-timing buckets, and silence — selectable via --signals (default all)
  • inputs that elicit new behaviour become corpus seeds whose lineage is prioritised for further mutation; --corpus <dir> persists the corpus (raw seed files plus a lineage.json manifest) and reloads seed bytes for a new campaign; --max-corpus caps retained seeds (lowest-scoring pruned first)
  • the campaign is bounded by --max-iterations and/or --max-seconds; the envelope reports iterations, new_behaviour_count, corpus_size, unique_markers, stop_reason, and a findings list
  • honours the active-transmit safety model (--ack-active, --rate pacing); --dry-run plans the campaign (planned mutations, mode: dry_run) without opening the transport. Structured errors: FUZZ_GUIDED_INVALID_SIGNALS, FUZZ_GUIDED_INVALID_ID (exit 1), FUZZ_GUIDED_TRANSPORT_FAILED (exit 2)
  • the fuzz_guided MCP tool is gated like other active tools (mandatory ack_active=true, dry_run defaulting to true)

Durable evidence:

Active fuzz guided runs archive each finding before the next transmission under --findings-dir, <corpus>/findings, or ~/.canarchy/findings (in that order). Use the returned archive_path and campaign_id to inspect campaign.json and finding-*.json offline. Findings retain payload/response evidence and lineage after corpus pruning; storage failures stop transmission. Dry-run creates no archive. MCP accepts findings_dir and retains its acknowledgement gate and dry-run default.

Each finding adds data (exact transmitted hex), parent_data, serialized observation frames/elapsed/silence, and a campaign-qualified finding_id. The manifest records the tool/schema version, initial seeds, explicit effective settings and transport window; unavailable target firmware is null. Non-finite --rate or --max-seconds values return FUZZ_GUIDED_INVALID_TIMING (exit 1) before archive creation, including in dry-run. Raw adapter I/O errors retain FUZZ_GUIDED_TRANSPORT_FAILED; only archive/corpus operations produce persistence errors.

Errors return archive_path, campaign_id (if initialized), and archived_finding_count. Storage failure is FUZZ_GUIDED_PERSISTENCE_FAILED (exit 2); keyboard interruption is FUZZ_GUIDED_INTERRUPTED (exit 1). Completed records remain available even without a final result/corpus save.

Offline inspection (replace paths with the returned archive and selected record):

jq '{campaign_id, canarchy_version, config, initial_seeds}' /path/to/archive/campaign.json
jq '{finding_id, data, parent_id, parent_data, new_markers, observation}' /path/to/archive/finding-00000002.json

To plan a single-input reproduction, copy the recorded ID/type and data into canarchy send <interface> <id> <data> --dry-run --json (add --extended for an extended identifier). Review the plan and target setup first. Actual sending uses the normal active-transmit acknowledgement gate. A single payload does not recreate ECU state or the full campaign history. Inspection never opens a bus. Archives are not automatically pruned; retain or remove them explicitly.

fuzz identify

Narrow a fuzz log to the culprit frame by replaying bisected windows and recording effect/no-effect observations.

canarchy fuzz identify <log> [--interface can0] [--observations FILE] [--observe effect|no-effect ...]
                       [--rate 100] [--max-window N] [--ack-active] [--dry-run] [--json|--jsonl|--text]

Notes:

  • <log> is a candump capture or a JSONL fuzz log / replay plan (one CAN-frame object per line, with top-level or payload-nested arbitration_id + data)
  • the workflow bisects the log: each round replays the lower half of the current candidate range, and the operator records whether the effect reproduced. Mark observations non-interactively with --observe effect|no-effect (repeatable) and/or a JSON --observations file (["no-effect", "effect", ...])
  • one round per invocation: with an --interface and without --dry-run it replays the next window live (behind the active-transmit safety model), then reports the candidate range / next window so you record an observation and re-invoke. With a full observation sequence supplied up front it resolves the culprit with no transmission
  • JSON output includes next_window / replayed_window, observations, candidate_lo/candidate_hi/candidate_frames, resolved/culprit, confidence, rationale, and provenance (source, frame_count, planned_rounds)
  • --max-window refuses to replay a window larger than N frames (FUZZ_IDENTIFY_WINDOW_TOO_LARGE); invalid logs/observations return FUZZ_IDENTIFY_LOG_UNAVAILABLE / FUZZ_IDENTIFY_INVALID_LOG / FUZZ_IDENTIFY_INVALID_OBSERVATION (exit 1)
  • fuzz identify is a CLI-only operator workflow and is not exposed as an MCP tool

mcp serve

Start the MCP server over stdio.

canarchy mcp serve

Notes:

  • this command does not accept output flags
  • the current MCP tool surface is a curated non-interactive subset of the CLI, not every implemented command
  • the server owns stdin as its JSON-RPC transport, so the - stdin sentinel is refused on every MCP file/source parameter with error code STDIN_MCP_EXCLUDED; the CLI stdin pipelines (--file -, --stdin) are unaffected

mcp install

Write the canarchy MCP server block into a client configuration file.

canarchy mcp install --client {claude-desktop,claude-code} [--config-path PATH] \
    [--command COMMAND] [--dry-run] [--ack] [--json|--jsonl|--text]

Flags:

  • --client {claude-desktop,claude-code} — required; selects the target client. claude-desktop resolves the per-platform config path (macOS / Windows / Linux); claude-code writes a project-scoped .mcp.json in the current directory.
  • --config-path PATH — override the auto-detected config path.
  • --command COMMAND — the command the client runs for the server (default canarchy; use an absolute venv path when canarchy is not on PATH).
  • --dry-run — print the would-write config without touching disk.
  • --ack — skip the YES confirmation prompt and write immediately.

Behavior:

  • merges the mcpServers.canarchy entry without disturbing other servers
  • treats an identical existing entry as a no-op (action: unchanged)
  • refuses to overwrite a different existing canarchy entry
  • action in the envelope data is one of create, update, unchanged, or planned (dry-run)
  • this command is CLI-only and is not exposed as an MCP tool (writing a client config is a user action)

Structured error codes: MCP_INSTALL_CONFLICT, MCP_INSTALL_INVALID_CONFIG, MCP_INSTALL_DIR_MISSING, MCP_INSTALL_READ_FAILED, MCP_INSTALL_WRITE_FAILED, MCP_INSTALL_DECLINED.


Output Modes

All commands support:

  • --json
  • --jsonl
  • --text

--text is the default when no output mode is specified. --table remains accepted as a compatibility alias for --text, but new examples and automation should use --text.

Current behavior:

  • --json emits one structured JSON object
  • --jsonl emits one JSON object per line
  • event-producing commands emit each event as its own JSON line; command warnings that are not already events are emitted as alert event lines
  • event-less successful commands emit a single result object line
  • failed commands emit a single error result object line
  • --text emits a human-readable summary view, with protocol-aware pretty-printing for J1939 monitor and decode workflows

J1939 --text output includes:

  • PGN
  • source address
  • destination address when present, otherwise broadcast
  • priority
  • CAN identifier
  • payload bytes

Argument Errors

Argument-parsing failures follow the same output contract as every other failure. canarchy stats --unknown-option --json returns the canonical error envelope as JSON, not a text block — this holds for an unrecognised option, an unknown command or subcommand, a missing required argument, and a value that fails type conversion. The envelope carries command: "cli" (the failure happened before a command was identified), the error code INVALID_ARGUMENTS, argparse's message verbatim, and exit code 1:

{
  "ok": false,
  "command": "cli",
  "data": {},
  "warnings": [],
  "errors": [
    {
      "code": "INVALID_ARGUMENTS",
      "message": "unrecognized arguments: --unknown-option",
      "hint": "Run `canarchy --help` to inspect the available commands and flags."
    }
  ]
}

The output flags are mutually exclusive, so passing more than one is itself an argument error. The envelope reporting it is rendered using a fixed precedence — --json beats --jsonl beats --text beats --table — independent of the order the flags appear in. canarchy stats --file capture.log --jsonl --json therefore exits 1 with a JSON envelope whose message is argument --json: not allowed with argument --jsonl.

--help and --version are not errors: argparse prints them as text and exits 0.

JSON Result Shape

Successful --json output uses this shape:

{
  "ok": true,
  "command": "capture",
  "data": {},
  "warnings": [],
  "errors": []
}

Error --json output and event-less/error --jsonl output use this shape:

{
  "ok": false,
  "command": "decode",
  "data": {},
  "warnings": [],
  "errors": [
    {
      "code": "DBC_LOAD_FAILED",
      "message": "Failed to parse DBC file.",
      "hint": "Validate the DBC syntax and line endings."
    }
  ]
}

Event Types In Structured Output

Implemented commands currently emit these event types:

  • frame
  • decoded_message
  • signal
  • j1939_pgn
  • j1587_parameter
  • j2497_message
  • uds_transaction
  • xcp_transaction
  • xcp_measurement
  • replay_event
  • alert

Exit Codes

  • 0 success
  • 1 user, input, or usage error
  • 2 backend or transport error
  • 3 decode, schema, or DBC error
  • 4 partial success

Representative failures:

  • INVALID_ARGUMENTS => exit code 1
  • INVALID_RATE => exit code 1
  • TRANSPORT_UNAVAILABLE => exit code 2
  • CAPTURE_SOURCE_UNAVAILABLE => exit code 2
  • DBC_LOAD_FAILED => exit code 3
  • DBC_SIGNAL_INVALID => exit code 3

Examples

Transport Capture

canarchy capture can0 --json

Transport Stats

canarchy stats --file tests/fixtures/sample.candump --json

Capture Metadata

canarchy capture-info --file tests/fixtures/sample.candump --json

Deterministic Replay

canarchy replay --file tests/fixtures/sample.candump --rate 0.5 --json

J1939 Monitor

canarchy j1939 monitor --json

J1939 PGN Filter

canarchy j1939 monitor --pgn 65262 --json

DBC Decode

canarchy decode --file tests/fixtures/sample.candump --dbc tests/fixtures/sample.dbc --json
canarchy dbc search toyota --provider opendbc --json

DBC Provider Decode

canarchy decode --file tests/fixtures/sample.candump --dbc opendbc:toyota_tnga_k_pt_generated --json

Reverse-Engineering DBC Match

canarchy re match-dbc tests/fixtures/sample.candump --provider opendbc --limit 5 --json

DBC Encode

canarchy encode --dbc tests/fixtures/sample.dbc EngineStatus1 CoolantTemp=55 OilTemp=65 Load=40 LampState=1 --json

UDS Scan

canarchy uds scan can0 --json

Notes:

  • the result reports protocol_decoder as built-in by default
  • when the optional Scapy extra is installed, UDS transaction payloads may include summary-level request/response enrichment without changing the command surface

UDS Trace

canarchy uds trace can0 --json

Notes:

  • the result reports protocol_decoder as built-in by default
  • negative responses may include negative_response_code and negative_response_name

Dataset Analysis (CANdid)

The CANdid dataset (VehicleSec 2025) provides candump-format CAN logs ready for direct analysis:

# Summarize a CANdid capture
canarchy stats --file 2_driving_CAN.log --json
canarchy capture-info --file 2_driving_CAN.log --json

# Filter for specific IDs
canarchy filter 'id==0x123' --file 2_steering_CAN.log --json

# Reverse-engineering helpers
canarchy re entropy --file 2_driving_CAN.log
canarchy re counters --file 2_driving_CAN.log

# Inspect the catalog entry
canarchy datasets inspect catalog:candid --json

Session Save

canarchy session save lab-a --interface can0 --dbc tests/fixtures/sample.dbc --capture tests/fixtures/sample.candump --json

Session Research Record

canarchy j1939 summary --file tests/fixtures/sample.candump --json > summary.json
canarchy session attach lab-a --artifact summary.json --command "canarchy j1939 summary --file tests/fixtures/sample.candump --json" --embed --json
canarchy session verify lab-a --json
canarchy session bundle lab-a --output /tmp/lab-a-bundle.zip --json

Shell One-Shot Command

canarchy shell --command "capture can0 --text"

Current Gaps

These deeper capabilities are not fully implemented yet even where the command surface exists:

  • deeper live transport integration beyond the current python-can transport path
  • the follow-up active-transmit safety controls tracked in the fuzz section (configurable rate-cap ceiling, TOML target allowlist, explicit KILL_SWITCH_TRIGGERED alert)

Numeric CLI options must be finite: NaN and positive/negative infinity fail with a structured usage error before file processing or transport access. This includes --seconds, rates, gaps, durations, timeouts, and analytical thresholds. File --seconds 0 keeps its existing initial-timestamp window semantics; other documented zero/range rules are unchanged. Invalid floats are described in error text, never echoed as non-standard JSON numbers. DoIP ?timeout= also requires a finite positive value.