Agent Guide¶
AGENTS.md¶
Project¶
CANarchy is a CLI-first CAN security research toolkit with optional REPL and TUI front ends.
The implementation language is Python, and the project uses uv for dependency management, virtual environments, and packaging workflows.
The core design rule is simple:
The CLI is the contract. The REPL and TUI are views over the same engine.
The project is focused on:
- CAN and CAN FD workflows
- J1939-first heavy vehicle workflows
- security research and protocol exploration
- automation-friendly use by coding agents
- automation-friendly development by coding agents
- structured outputs suitable for pipelines and machine parsing
Project planning¶
GitHub Issues are the source of truth for project planning and task tracking.
Every change must be associated with an issue¶
This is a hard rule, not a suggestion.
- Before starting any new feature, bug fix, or non-trivial refactor, check whether an open issue already covers it.
- If no issue exists, create one with a clear title, description, and acceptance criteria before writing code.
- Every commit that implements or fixes something must reference the relevant issue number using
closes #N,fixes #N, orrefs #Nin the commit message. - Do not merge or push code changes that have no associated issue.
- Bug fixes discovered incidentally (e.g. while working on a different issue) get their own issue opened first, then fixed.
The only exceptions are:
* typo/whitespace-only changes in docs or comments
* changes to .gitignore or other non-functional config
Branch and pull-request workflow¶
This is a hard rule, not a suggestion.
- Before creating a branch, post a comment on the issue claiming it — for example: "Starting work on this; branch will be
<branch-name>." This prevents two agents or contributors from independently implementing the same issue. - For any non-trivial feature, bug fix, refactor, or documentation change, agents shall create and work from a dedicated branch rather than committing directly on
main. - Branch names should be short, descriptive, and tied to the issue when practical, for example
issue-110-j1939-compare. - When issue-scoped work is complete, agents shall push the branch and open a pull request unless the user explicitly asks for a direct push or direct commit flow.
- Pull requests should be the default handoff for review, CI, and merge discussion.
- Agents shall not merge their own pull requests unless the user explicitly asks them to do so.
- If urgent work must go directly to
main, the user shall explicitly request that exception.
Changelog policy¶
CHANGELOG.md follows the Keep a Changelog format. Every non-trivial change must be recorded in the [Unreleased] section before or alongside the commit that introduces it.
This is a hard rule, not a suggestion.
- Every new feature, bug fix, behaviour change, or significant documentation update must have a corresponding
CHANGELOG.mdentry under[Unreleased]. - Group entries under the standard headings:
Added,Changed,Deprecated,Removed,Fixed,Security, orDocumentation. - Write entries from the operator's perspective — describe what changed and why it matters, not what files were edited.
- Changelog entries must be committed in the same commit or PR as the change they describe. Do not leave the changelog update for a separate follow-up.
- When a release is cut, the
[Unreleased]section is promoted to a versioned heading. Do not manually create versioned headings outside of the release workflow. - The only exceptions are: typo/whitespace-only changes in docs or comments, changes to
.gitignoreor other non-functional config, and MkDocs nav or theme-only changes.
Versioning after release¶
This is a hard rule, not a suggestion.
- After cutting release
X.Y.Z, advancesrc/canarchy/__init__.pyonmaintoX.Y.(Z+1).dev0unless a different next-version target is explicitly planned and documented. - Do not leave
mainon the released version once unreleased work resumes. - Keep release tags on the stable release version only, such as
v0.4.0. - If the next intended release is a minor or major bump instead of the next patch version, document that decision explicitly and set the
.dev0version accordingly.
PR acceptance criteria¶
A PR is not ready to merge until all of the following are true.
This is a hard rule, not a suggestion.
| # | Gate | Notes |
|---|---|---|
| 1 | Issue referenced | Commit message contains closes #N, fixes #N, or refs #N |
| 2 | Tests pass | All existing tests pass; new behaviour has new tests |
| 3 | Changelog updated | [Unreleased] section reflects the change (see Changelog policy) |
| 4 | Design spec current | Any touched docs/design/ spec reflects the implemented behaviour — requirements updated, no stale wording |
| 5 | Test spec current | Any touched docs/tests/ spec reflects the actual test coverage — new TEST-* IDs added, traceability table updated |
| 6 | Agent guide current | If the change affects the command surface, MCP tools, output schema, or any workflow an agent would follow, AGENTS.md and docs/agents.md are updated |
| 7 | No stale documentation left | Verify that no other doc (architecture docs, tutorials, command_spec.md) references old behaviour that the PR changes |
When reviewing your own work before committing or pushing, explicitly check each gate in order. Do not defer documentation updates to a follow-up commit.
Other issue rules¶
- Use GitHub Issues to track planned work rather than ad hoc task lists in docs.
- Claim an issue before starting work. Post a comment on the issue as the very first action — before creating a branch or writing any code — stating that work is beginning and naming the intended branch. This is the coordination signal that prevents duplicate effort by other agents or contributors.
- When starting or completing work that relates to an issue, update the issue with progress or implementation notes.
- Commit and push the relevant code changes before closing an issue so the issue state matches the remote repository state.
- Close an issue when its scope and acceptance criteria have been satisfied.
- When creating a new issue, always include explicit acceptance criteria that define what must be true to close it.
- If code changes only partially satisfy an issue, leave the issue open and note the remaining work.
- If work for an issue is complete locally but has not yet been committed and pushed, explicitly offer to the user to commit and push the changes and then close or update the issue.
- After completing issue-scoped work, summarize what was implemented, recommend the most sensible next steps, and present those next steps as a concise multiple-choice menu the user can select from.
Recommended completion handoff when issue-scoped work is done locally¶
- State that the issue work is complete locally.
- Summarize the shipped changes and verification results.
- Offer to commit, push the branch, and open a pull request if that has not happened yet.
- If the branch and pull request already exist, offer to update or close the issue if still needed.
- Recommend the next 2–4 highest-value follow-up tasks.
- Present the next steps as a multiple-choice menu, for example:
A. commit, push the branch, and open a pull request B. start the next recommended issue C. refine docs or tests around the completed work D. inspect or review the implementation before moving on
Primary goals¶
- Build a stable, scriptable command surface for CAN security research.
- Make common analyst workflows easy from the terminal.
- Support agentic use through deterministic commands, structured output, and explicit error handling.
- Keep protocol logic in the core engine, not in the UI.
- Preserve parity across CLI, REPL, and TUI wherever practical.
Non-goals for the first versions¶
Do not try to do all of these immediately:
- Full OEM-specific protocol coverage
- Deep GUI-first workflows
- Large-scale cloud architecture
- Automatic “AI magic” without clear, inspectable outputs
- Feature parity with every existing CAN tool before the core model is stable
Product shape¶
CANarchy should be implemented as three layers:
1. Core engine¶
Responsible for:
- transport backends
- frame ingest and transmit
- decode/encode pipelines
- protocol state tracking
- replay and mutation
- analysis and reverse engineering helpers
- event generation
2. Command layer¶
Responsible for:
- canonical commands and subcommands
- validation of arguments
- output formatting modes
- exit codes
- scripting compatibility
3. Front ends¶
Responsible for presentation only:
- CLI
- REPL shell
- TUI
Front ends must not contain business logic that cannot also be reached through the CLI.
Front-end rules¶
CLI¶
The CLI is the authoritative interface.
Every important workflow must be reachable as a non-interactive command.
Examples:
canarchy capture can0 --jsonlcanarchy capture --jsonlwhen[transport].default_interfaceorCANARCHY_DEFAULT_INTERFACEis configuredcanarchy capture-info --file capture.log --jsoncanarchy decode --file capture.log --dbc truck.dbc --jsoncanarchy j1939 monitor --pgn 65262 --jsoncanarchy uds scan can0 --jsoncanarchy replay --file drive.log --rate 0.5
Single-interface transport commands may resolve their CAN interface from user config when the command-line value is omitted. The explicit command-line interface always has the highest precedence; use [transport].default_interface in ~/.canarchy/config.toml or CANARCHY_DEFAULT_INTERFACE for the fallback channel. This is separate from [transport].interface, which selects the python-can backend type such as socketcan, udp_multicast, pcan, vector, or kvaser. Use canarchy doctor for offline configured-backend dependency hints; live hardware access still requires operator-run validation against the adapter and bus.
For dashboard launchers, run canarchy web serve --file <capture> --bind 127.0.0.1:0 --json and read the startup envelope from stdout to obtain data.url. The complete startup result is flushed before the serving loop, including when stdout is a pipe; PYTHONUNBUFFERED is unnecessary. JSONL and human output are also flushed. Keep the subprocess alive while using its URL and terminate it when finished. HTTP request logging does not appear on structured stdout. This remains a CLI-only workflow.
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.
REPL¶
The REPL is a convenience layer for human operators.
The REPL should:
- reuse the same command parser where possible
- preserve context like active bus, loaded decode database, and session artifacts
- expose the same operations as the CLI with minimal drift
TUI¶
The TUI is a state and visualization surface over the same engine.
The TUI should:
- consume the same event stream model used by CLI/REPL
- trigger the same underlying commands/actions
- avoid introducing unique features that cannot be expressed as commands
The full-screen TUI shows non-event command answers, errors, help, and version text in a read-only result view. F2 switches between that view and the event panes; Esc returns to the panes. Event rows and live capture continue while results are open. Agents should still use non-interactive CLI or MCP output for automation.
The TUI's responsive workspaces are Traffic, Signals, J1939, UDS, and Findings (Alt+1–Alt+5). F3 expands the activity band; Enter shows the selected row's full fields on narrow terminals and Esc returns to the table. These presentation controls do not alter the CLI command contract or the capture lifecycle.
Traffic defaults to a bounded summary keyed by (bus, arbitration_id, is_extended_id); v switches to the chronological event log, and F4 freezes inspection independently of capture or returns live. The inspector shows complete raw hex/bit data, changed-byte offsets with a textual legend, decoded evidence when available, and recent history. /filter traffic uses the shared CLI frame-filter grammar for typed id==, pgn==, and sa== expressions; plain text remains a substring filter. The CLI filter command also accepts sa==<source-address> for extended J1939 frames. Invalid typed filters and unknown TUI sort fields are reported without changing the previous view state.
DBC decoded_message events with embedded frames populate the Traffic identifier summary and event log, with child signals correlated by source, frame index, and message name. Live follow selects only visible traffic under the active filter; returning live from a historical log row advances to the newest visible event.
DBC decoded_message and signal events share a zero-based payload.frame_index local to each decode invocation. The TUI combines a parent/child signal only when source, frame_index, message_name, and signal_name match; repeated equal-valued frames stay separate. Missing indexes are not inferred from values. Decoded signal events inherit the source-frame timestamp, including zero; unknown timestamps remain null without substituting wall-clock decode time. Signal-only streams preserve the source time series without parent joins.
Initial capability priorities¶
P0¶
- CAN / CAN FD capture
- transmit/send
- replay
- filtering
- stats
- structured export (
json,jsonl) - DBC-backed decode and encode
- J1939 monitor / decode / PGN-first workflows
- clear exit codes and error schema
P1¶
- UDS scan and trace support (CAN/ISO-TP and DoIP —
uds scan|trace doip://host:port?logical_address=0x0E80) - session save/load
- SQLite export
- remote backends
- mutation/fuzzing primitives
- reverse engineering helpers
P2¶
- TUI dashboard
- plugin SDK
- additional output sinks such as MQTT/Kafka/webhooks
- advanced anomaly detection and signal inference
Security research focus¶
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.
CANarchy is intended for defensive research, protocol analysis, lab experimentation, red-team style validation, and tool-assisted reverse engineering.
When implementing features, prefer:
- reproducibility
- evidence capture
- traceability
- safe defaults
- explicit operator intent for active transmission and fuzzing
Suggested safeguards:
- make active transmit/fuzz commands obviously distinct from passive commands
- support dry-run modes where possible
- log enough metadata for lab replay and reporting
Architectural principles¶
1. Structured events over raw text¶
Internally, the system should model events such as:
- frame
- decoded message
- signal value
- J1939 PGN/SPN observation
- UDS request/response transaction
- anomaly
- replay action
- fuzz action
- alert
Prefer typed event objects over free-form strings.
For protocol transactions that can be partially reconstructed from captured traffic, include explicit completeness fields instead of implying that every decoded payload is whole.
Where optional protocol enrichers are present, such as a Scapy-backed diagnostic adapter for UDS, surface them through stable summary-level fields rather than leaking third-party runtime objects into command output.
2. Human output must never break machine output¶
Every command should support explicit output modes:
--json--jsonl--text
Do not mix human decoration into JSON output.
3. Deterministic behavior matters¶
Commands should behave predictably.
Avoid:
- hidden prompts in non-interactive mode
- unstable field names
- ambiguous time formats
- random output ordering unless explicitly requested
4. Stable command grammar¶
Prefer a command layout like:
<domain> <action>- or
<action> <object>only when very obvious
Examples:
j1939 monitorj1939 decodej1939 comparej1939 inventoryskills searchuds scanre signalssession save
5. Protocol semantics are first-class¶
Do not force users to stay at the raw-frame layer when protocol-aware workflows exist.
Examples:
- allow PGN/SPN-first commands for J1939
- allow request/response transaction views for UDS
- allow decode-aware filtering
Coding guidelines¶
General¶
- Favor readability and explicitness over cleverness.
- Keep modules small and focused.
- Add tests for protocol parsing, decode logic, and CLI behavior.
- Prefer pure functions for transforms and protocol analysis.
- Keep transport adapters separate from semantic layers.
Error handling¶
All errors should be actionable.
At minimum, errors should communicate:
- category
- message
- likely cause
- retry or corrective hint when appropriate
Prefer structured errors internally and in JSON output.
Logging¶
- Use structured logging internally.
- Keep logs useful for replay and debugging.
- Avoid noisy logs in default CLI usage.
Configuration¶
- Prefer explicit CLI flags first.
- Add config files only where they reduce repetition without hiding behavior.
- Make the effective configuration inspectable.
Output and exit code conventions¶
Suggested exit codes:
0success1user/input/usage error2backend or transport error3decode/schema/plugin error4partial result / partial success
Suggested JSON result shape:
{
"ok": true,
"command": "j1939 monitor",
"data": {},
"warnings": [],
"errors": []
}
Suggested JSON error shape:
{
"ok": false,
"command": "decode",
"errors": [
{
"code": "DBC_LOAD_FAILED",
"message": "Failed to parse DBC file.",
"hint": "Validate file format and line endings."
}
]
}
Argument-parsing failures use the same envelope, so one error parser covers
every failure. An unrecognised option, an unknown command or subcommand, a
missing required argument, or a value that fails type conversion returns
command: "cli", code INVALID_ARGUMENTS, and exit code 1 in the requested
format — canarchy stats --unknown-option --json emits JSON, not a text
block. The output flags are mutually exclusive, so passing more than one is
itself an argument error; the envelope reporting it is rendered by the fixed
precedence --json > --jsonl > --text > --table, independent of order.
--help and --version remain plain text with exit code 0. See
docs/design/cli-parse-errors.md.
Proposed initial command tree¶
canarchy
capture
capture-info
send
replay
filter
stats
decode
encode
skills
provider list
search
fetch
cache list
cache refresh
plugins
list
info
enable
disable
datasets
provider list
search
inspect
fetch
cache list
cache refresh
convert
stream
replay
export
session
save
load
show
verify
annotate
attach
bundle
import
j1939
monitor
decode
compare
pgn
spn
tp
dm1
summary
inventory
uds
scan
trace
services
subservices
ecu-reset
tester-present
security-seed
dump-dids
read-memory
auto
re
signals
counters
entropy
correlate
shell
tui
This tree is a starting point, not a lock.
Active-transmit MCP tools (send, generate, gateway, replay, sequence_replay, xcp_scan, fuzz_guided, and fuzz payload|replay|arbitration-id|signal|spn) are behind the active-transmit safety model — mandatory ack_active=true with dry_run defaulting to true. The authoritative CLI-to-MCP coverage matrix (exposed / excluded / deferred) is maintained in docs/design/mcp-server.md, and tests/test_mcp.py enforces that every implemented command is either exposed or a documented exclusion (shell, tui, web serve, cannelloni send, mcp serve, mcp install, completion, datasets stream, dbc generate-c, plugins enable, plugins disable, the active uds workflows uds subservices|ecu-reset|tester-present|security-seed|dump-dids|read-memory|auto, the active xcp info / xcp dump, the active doip command group, and fuzz identify). The uds_scan / uds_trace tools are exposed for CAN interfaces but refuse a doip:// target with DOIP_MCP_EXCLUDED, since DoIP is active TCP egress to an arbitrary host and stays a CLI-only operator action. The active UDS workflows (uds subservices, ecu-reset, tester-present, security-seed, dump-dids, read-memory, auto) transmit invasive diagnostic requests and are CLI-only operator actions behind the active-transmit gate; the reference uds services catalog stays exposed (its active-probe mode only activates when a CLI caller supplies an interface on the command line; a configured default interface never promotes it, so MCP uds_services is reference-only regardless of local configuration). xcp info (capability queries) and xcp dump (bounded memory upload) connect to a slave and are likewise CLI-only; the broadcast xcp scan stays exposed. The dedicated doip command group (doip discovery|services|ecu-reset|tester-present|security-seed|dump-dids) is also CLI-only — active network egress (UDP discovery + TCP diagnostic sessions) behind the active-transmit gate. fuzz identify is a stateful, multi-round human-in-the-loop replay/narrowing workflow (one bisected window replayed per invocation) and stays CLI-only.
MCP tool results set isError=true whenever the canonical JSON envelope has ok=false, including command failures, excluded targets, missing active-transmit acknowledgement, and isolated unexpected exceptions. Codes, messages, and hints remain in the JSON text. Successful calls set isError=false. SDK input-schema validation runs before the command handler: missing required fields or invalid schema types return isError=true with SDK validation text rather than a CANarchy JSON envelope. Correct the input and retry; ordinary errors leave the session available for later calls.
For plugin automation, agents can use MCP plugins_list / plugins_info or CLI canarchy plugins list|info --json to inspect discovered Python entry-point plugins. Plugin toggles are user configuration actions; use CLI canarchy plugins enable|disable <name> only when explicitly requested by the operator.
For dataset automation, agents should prefer MCP dataset tools when available, or explicit CLI JSON output otherwise. datasets_search / datasets search --json and datasets_inspect / datasets inspect --json include stable machine fields: ref, is_replayable, is_index, default_replay_file, download_url_available, and source_type. datasets_fetch distinguishes curated indexes from normal dataset entries with is_index, index_instructions, and download_instructions, and reports data_is_local: true when the fetch materialised real bytes into the cache rather than recording provenance for a remote file. When data_is_local is true, next_steps names the local-file commands to run against cache_path — datasets download and datasets replay do not apply and will fail with DATASET_REPLAY_UNAVAILABLE. Use MCP datasets_replay_plan or CLI datasets replay --dry-run --json for safe replay preflight; use datasets replay --list-files --json to choose a replay file and --file <id-or-name> to select it. Use --max-frames or --max-seconds to bound replay. For catalog:comma-car-segments, use --platform <name> to filter dynamic HuggingFace segment manifests and --limit <n> to bound file listings before selecting a segment. Use datasets stream --max-frames <n> to bound local downloaded dataset-file streaming; --chunk-size controls JSONL provenance chunk metadata and is not a frame limit. comma-rlog streaming requires optional openpilot LogReader support (uv pip install git+https://github.com/commaai/openpilot.git on Python 3.12.x) and otherwise returns COMMA_RLOG_SUPPORT_UNAVAILABLE. Actual dataset frame streaming remains CLI-only. Curated index entries that cannot be replayed return DATASET_INDEX_NOT_REPLAYABLE.
Every dataset in the catalog provider downloads from a host (zenodo.org, figshare.com, huggingface.co, ocslab.hksecurity.net) that a typical sandboxed agent environment blocks, so datasets fetch followed by a replay fails there with a transport error. When there is no egress, use the offline provider instead: datasets search --provider offline --json lists synthetic datasets that generate locally and need no network. datasets fetch offline:<name> writes real data into the cache and returns its path in cache_path, after which the local-file commands (datasets convert, datasets stream, capture-info, stats, j1939 summary, replay --file) work normally. Offline datasets carry synthetic: true in the machine fields, a licence string identifying them as synthetic, and a SYNTHETIC: description prefix. The data has real protocol structure but is not vehicle behaviour: use it to exercise tooling, never report analysis of it as a research finding. Current offline datasets are can-basic (candump, with a discoverable counter), j1939-basic (candump, with BAM/TP and a DM1 active fault), can-intrusion (hcrl-csv, attack-labelled), and signal-decoded (decoded-signal-csv).
A bare dataset ref (no provider: prefix) resolves against providers in order, and datasets_provider_list / datasets provider list --json reports that effective order as search_order plus a per-provider order index. The default is catalog before offline, so a bare ref prefers a real dataset over synthetic data of the same name; an operator can reorder it with [datasets].search_order in ~/.canarchy/config.toml. Prefer a prefixed ref (catalog:road, offline:can-basic) when the provider matters. A provider name in that config that does not exist fails every datasets command with DATASET_PROVIDER_NOT_FOUND (exit 1); a malformed value fails with DATASET_SEARCH_ORDER_INVALID.
For DBC reconnaissance, agents can use canarchy dbc inspect <dbc> --layout --json or MCP dbc_inspect with layout=true to retrieve cantools-rendered bit-layout diagrams, signal trees, and choice tables as structured message fields.
For compare, identify each message by (arbitration_id, is_extended_id). Standard and extended frames with the same numeric ID have separate rows. id_count and summary.unique_ids count these pairs. Use summary *_identifiers arrays (objects with arbitration_id and is_extended_id) for unambiguous category membership; legacy *_ids arrays remain sorted, deduplicated numeric views. Summaries include all findings even when --top limits rows.
MCP output caps measure final canonical CANarchy JSON tool envelopes in UTF-8, including truncation metadata and warnings, excluding transport wrapping and SDK-generated schema-validation or protocol errors. CANARCHY_MCP_MAX_RESPONSE_BYTES defaults to 512000 and requires at least 1024 bytes; smaller positive values fail before startup. Truncation metadata lists only paths present in the returned data. Oversized scalar data or diagnostics may become an actionable stub; compact diagnostics preserve a short original error code, or use RESPONSE_TRUNCATED when no bounded code is available. Re-run the equivalent CLI command for the full result.
For stdin pipelines, capture-info --file -, stats --file -, and filter --file - read candump text from stdin. filter --stdin, decode --stdin, and j1939 decode --stdin read JSONL FrameEvents from stdin regardless of output format. These pipelines are CLI-only: the MCP server owns stdin as its JSON-RPC transport, so passing - to any MCP file or source parameter is refused before the command runs with error code STDIN_MCP_EXCLUDED and the MCP tool-failure flag set. MCP callers must pass a real file path; write a piped stream to a file first.
For security workflow examples that combine commands into complete agent tasks, see docs/security-use-cases.md. The primary documented workflows are CAN/J1939 capture triage, dataset-driven IDS experimentation, DBC-assisted signal reconnaissance, protocol-aware incident reporting, and safe replay/regression testing.
J1939 expectations¶
J1939 should be treated as a first-class workflow, not an afterthought.
Priorities:
- PGN-first filtering
- SPN presentation where decode data is available
- source address tracking
- TP/BAM reassembly support
- DM message visibility
- ECU/node activity summaries
The user should not be forced to manually reason from raw 29-bit IDs for common J1939 tasks.
Reverse engineering expectations¶
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.
Reverse engineering features should be evidence-driven and explainable.
Good early features:
- field entropy ranking
- likely counter detection
- likely checksum detection
- correlation against known external series
- changing-bit analysis
- signal boundary suggestions
Do not present guesses as facts. Always expose confidence and rationale where possible.
TUI expectations¶
The TUI should be useful for live analysis, demos, and triage.
Good initial panes:
- bus/interface status
- live traffic table
- decoded signals
- J1939 PGN/SPN activity
- node list
- alerts/events
- command entry area
The TUI should subscribe to the same event model used elsewhere.
Testing expectations¶
At minimum, cover:
- frame parsing and formatting
- J1939 ID decomposition
- DBC-backed decode behavior
- replay timing behavior
- CLI argument validation
- JSON output stability
- error schema behavior
Where possible, use fixtures for:
- representative CAN logs
- representative J1939 traces
- malformed inputs
- edge cases like extended IDs, CAN FD, transport protocol fragmentation
Documentation expectations¶
Documentation should be written for three audiences:
1. Operators¶
Show practical commands and workflows.
2. Developers¶
Explain architecture, module responsibilities, and extension points.
3. Agents¶
Keep command help, output schemas, and command behavior explicit and stable.
Prefer example-heavy docs.
Design and architecture documents¶
CANarchy maintains living specification documents alongside the code. These documents are the authoritative record of how the system is designed to work.
Document types¶
Architecture documents (docs/architecture/)
Describe the overall structure and module responsibilities. Each document should cover:
- the problem the component solves
- its boundaries and responsibilities
- how it interacts with adjacent components
- key design decisions and the reasons for them
- what is intentionally out of scope
Software design specs (docs/design/)
Describe the intended behavior of a specific feature or subsystem before or during implementation. Each spec should include:
- document control metadata including current status and affected command surface
- the goal and user-facing motivation
- explicit requirement IDs in a stable format such as
REQ-<AREA>-NN - the proposed command surface or API shape
- data models and event types involved
- output format definitions (JSON schema or representative examples)
- error cases and expected error codes
- open questions or deferred decisions
Test specs (docs/tests/)
Describe the test strategy and coverage expectations for a component or feature. Each test spec should include:
- document control metadata including the related design spec
- explicit test case IDs in a stable format such as
TEST-<AREA>-NN - what behaviors must be covered
- requirement-to-test traceability mapping back to the design spec requirement IDs
- representative test cases including happy path, edge cases, and failure modes
- fixture requirements
- what is explicitly not tested and why
Spec language standard¶
All design specs and test specs must use the formats defined in docs/spec-template.md.
Design specs shall write requirements using EARS (Easy Approach to Requirements Syntax):
| EARS type | Template |
|---|---|
| Ubiquitous | The system shall … |
| Event-driven | When \<trigger>, the system shall … |
| State-driven | While \<state>, the system shall … |
| Optional feature | Where \<feature> is specified, the system shall … |
| Unwanted behaviour | If \<condition>, the system shall … |
Each requirement row in the table shall include a Type column identifying which EARS pattern applies.
Test specs shall write test cases using Gherkin Given/When/Then syntax inside a fenced gherkin block, followed by a **Fixture:** line naming the required files or environment.
Rules for agents¶
- When implementing a new feature or command, check
docs/design/for an existing spec before writing code. If a spec exists, implement against it. If it conflicts with the code, flag the conflict rather than silently diverging. - When no spec exists for a significant new feature, create one in
docs/design/before or alongside the implementation. Followdocs/spec-template.mdfor the required sections, requirement IDs (REQ-<AREA>-NN), and EARS language. - When adding new protocol logic, transport backends, or output formats, update or create the relevant architecture document in
docs/architecture/. - After implementing a feature, verify the test spec in
docs/tests/matches what was actually tested, includes test IDs (TEST-<AREA>-NN), uses Gherkin Given/When/Then, and traces back to the design-spec requirement IDs. Update it if coverage changed. - Specs are living documents. Update them when the implementation changes rather than letting them drift.
- Do not create specs for trivial changes (single-function fixes, minor output tweaks). Reserve them for features that affect the command surface, data model, or module boundaries.
- Before marking work complete or opening a PR, run through the PR acceptance criteria checklist above. Documentation currency (gates 4–7) is a required part of acceptance, not optional follow-up work.
Preferred development style for agents¶
When proposing code changes or new modules, agents should:
- preserve CLI stability
- avoid leaking UI logic into core modules
- prefer structured outputs over formatted prose
- add tests with new behavior
- document new commands and output fields
- keep protocol-specific logic in well-named modules
- avoid unnecessary dependencies in the core runtime
When uncertain, agents should optimize for:
- CLI reliability
- output stability
- protocol correctness
- architecture clarity
- UI polish
Initial implementation suggestion¶
A reasonable first milestone is:
- core frame/event model
- SocketCAN capture/send/replay
- JSON/JSONL output modes
- DBC decode pipeline
- basic J1939 decomposition and monitor command
- simple session model
- shell scaffolding
Only after the command and event model feel stable should the project invest heavily in TUI and plugin work.
Working summary¶
CANarchy should become:
A CLI-first CAN security research environment with structured outputs, protocol-aware workflows, and shared core logic across CLI, REPL, and TUI.
When making design choices, preserve the following order of importance:
- command clarity
- structured outputs
- protocol correctness
- session reproducibility
- front-end parity
- visual polish
For compare, identify each message by (arbitration_id, is_extended_id). Standard and extended frames with the same numeric ID have separate rows. id_count and summary.unique_ids count these pairs. Use summary *_identifiers arrays (objects with arbitration_id and is_extended_id) for unambiguous category membership; legacy *_ids arrays remain sorted, deduplicated numeric views. Summaries include all findings even when --top limits rows.
For dashboard launchers, run canarchy web serve --file <capture> --bind 127.0.0.1:0 --json and read the startup envelope from stdout to obtain data.url. The complete startup result is flushed before the serving loop, including when stdout is a pipe; PYTHONUNBUFFERED is unnecessary. JSONL and human output are also flushed. Keep the subprocess alive while using its URL and terminate it when finished. HTTP request logging does not appear on structured stdout. This remains a CLI-only workflow.
MCP Server Integration¶
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.
CANarchy ships a native Model Context Protocol (MCP) server. Agents that support MCP tool calls can connect directly instead of spawning subprocesses and parsing stdout.
For security workflow examples that combine CLI/MCP calls into complete analyst tasks, see Security Use Cases With Coding Agents.
Starting the Server¶
canarchy mcp serve
The server communicates over stdio using JSON-RPC 2.0 and runs until the client disconnects.
Claude Desktop Configuration¶
The fastest way to wire CANarchy into a client is the canarchy mcp install
helper, which merges the mcpServers.canarchy block for you (see
Install the CANarchy MCP server):
canarchy mcp install --client claude-desktop --dry-run # preview
canarchy mcp install --client claude-desktop # write (prompts; --ack to skip)
canarchy mcp install --client claude-code --ack
It is CLI-only (writing a client config is a user action, so it is not an
MCP tool) and refuses to overwrite a different existing canarchy entry.
To wire it up by hand instead, add the block directly:
{
"mcpServers": {
"canarchy": {
"command": "canarchy",
"args": ["mcp", "serve"]
}
}
}
With uv in a project environment:
{
"mcpServers": {
"canarchy": {
"command": "uv",
"args": ["run", "canarchy", "mcp", "serve"],
"cwd": "/path/to/your/project"
}
}
}
Available Tools¶
The current MCP surface exposes a curated non-interactive subset of the CLI. Spaces in command names become underscores:
For MCP tools that accept a single CAN interface, omit the interface argument only when [transport].default_interface or CANARCHY_DEFAULT_INTERFACE is configured. Explicit MCP interface arguments take precedence over the configured default. [transport].interface is the python-can backend type (socketcan, udp_multicast, pcan, vector, kvaser, etc.) and is not the CAN channel fallback. doctor can report offline configured-backend dependency hints, but it does not open hardware.
Active-transmit MCP tools (send, generate, simulate, gateway, replay, sequence_replay, and fuzz_*) require ack_active=true. Their dry_run argument defaults to true, so agent calls plan without transmitting unless an operator explicitly authorizes live transmission with dry_run=false.
For DBC reconnaissance, dbc_inspect accepts layout=true to include cantools-rendered message bit diagrams, signal trees, and choice tables as structured strings on each message payload.
DBC decode emits a decoded_message event and individual signal events for the same source frame. Their payloads share a zero-based frame_index local to that decode invocation; use (source, frame_index, message_name, signal_name) to correlate them. Equal values at different indexes are distinct observations. Signal timestamps inherit the source-frame timestamp, including zero, and remain null when unknown; no wall-clock decode time is substituted. Select signal events directly for time-series analysis without joining parent events, and do not infer missing identities from matching values.
| MCP tool | CLI equivalent |
|---|---|
capture |
canarchy capture |
send |
canarchy send |
generate |
canarchy generate |
gateway |
canarchy gateway |
replay |
canarchy replay |
sequence_replay |
canarchy sequence replay |
simulate |
canarchy simulate |
filter |
canarchy filter |
stats |
canarchy stats |
capture_info |
canarchy capture-info |
decode |
canarchy decode |
encode |
canarchy encode |
dbc_inspect |
canarchy dbc inspect |
dbc_signals |
canarchy dbc signals |
dbc_convert |
canarchy dbc convert |
dbc_provider_list |
canarchy dbc provider list |
dbc_search |
canarchy dbc search |
dbc_fetch |
canarchy dbc fetch |
dbc_cache_list |
canarchy dbc cache list |
dbc_cache_prune |
canarchy dbc cache prune |
dbc_cache_refresh |
canarchy dbc cache refresh |
datasets_provider_list |
canarchy datasets provider list |
datasets_search |
canarchy datasets search |
datasets_inspect |
canarchy datasets inspect |
datasets_fetch |
canarchy datasets fetch |
datasets_cache_list |
canarchy datasets cache list |
datasets_cache_refresh |
canarchy datasets cache refresh |
datasets_replay_plan |
canarchy datasets replay --dry-run |
export |
canarchy export |
session_save |
canarchy session save |
session_load |
canarchy session load |
session_show |
canarchy session show |
session_verify |
canarchy session verify |
session_annotate |
canarchy session annotate |
session_attach |
canarchy session attach |
session_bundle |
canarchy session bundle |
session_import |
canarchy session import |
j1939_monitor |
canarchy j1939 monitor |
j1939_decode |
canarchy j1939 decode |
j1939_pgn |
canarchy j1939 pgn |
j1939_spn |
canarchy j1939 spn |
j1939_tp |
canarchy j1939 tp sessions |
j1939_dm1 |
canarchy j1939 dm1 |
j1939_summary |
canarchy j1939 summary |
j1939_inventory |
canarchy j1939 inventory |
uds_scan |
canarchy uds scan |
uds_trace |
canarchy uds trace |
uds_services |
canarchy uds services |
xcp_scan |
canarchy xcp scan |
xcp_trace |
canarchy xcp trace |
xcp_read |
canarchy xcp read |
xcp_commands |
canarchy xcp commands |
j1587_decode |
canarchy j1587 decode |
j1587_pids |
canarchy j1587 pids |
j2497_decode |
canarchy j2497 decode |
j2497_mids |
canarchy j2497 mids |
config_show |
canarchy config show |
doctor |
canarchy doctor |
re_anomalies |
canarchy re anomalies |
re_correlate |
canarchy re correlate |
re_counters |
canarchy re counters |
re_entropy |
canarchy re entropy |
re_match_dbc |
canarchy re match-dbc |
re_shortlist_dbc |
canarchy re shortlist-dbc |
j1939_tp_compare |
canarchy j1939 tp compare |
j1939_faults |
canarchy j1939 faults |
j1939_compare |
canarchy j1939 compare |
j1939_map |
canarchy j1939 map |
re_signals |
canarchy re signals |
re_corpus |
canarchy re corpus |
re_suggest |
canarchy re suggest (heuristic path only) |
plot |
canarchy plot |
cannelloni_decode |
canarchy cannelloni decode |
datasets_convert |
canarchy datasets convert |
datasets_replay_files |
canarchy datasets replay --list-files |
skills_provider_list |
canarchy skills provider list |
skills_search |
canarchy skills search |
skills_fetch |
canarchy skills fetch |
skills_cache_list |
canarchy skills cache list |
skills_cache_refresh |
canarchy skills cache refresh |
plugins_list |
canarchy plugins list |
plugins_info |
canarchy plugins info |
| fuzz_payload | canarchy fuzz payload |
| fuzz_replay | canarchy fuzz replay |
| fuzz_arbitration_id | canarchy fuzz arbitration-id |
| fuzz_signal | canarchy fuzz signal |
| fuzz_spn | canarchy fuzz spn |
| fuzz_guided | canarchy fuzz guided |
| compare | canarchy compare |
Current exclusions:
- dataset streaming commands that emit frame records, such as
datasets streamand non-dry-rundatasets replay -
interactive or service commands such as
shell,tui,web serve,mcp serve, andmcp install -
cannelloni send— active UDP egress to an arbitrary host:port; CLI-only operator action (cannelloni decodeis exposed) doip://targets onuds_scan/uds_trace— DoIP routes UDS over active TCP egress to an arbitrary host; the tools stay CAN-interface-only and refuse adoip://interface withDOIP_MCP_EXCLUDED. Run DoIP scans/traces from the CLI as an operator action- the dedicated
doipcommand group (doip discovery,doip services,doip ecu-reset,doip tester-present,doip security-seed,doip dump-dids) — active network egress (UDP vehicle-identification discovery + TCP diagnostic sessions), CLI-only operator actions behind the active-transmit gate completion, which emits a raw shell script rather than a JSON envelopedbc generate-c, which generates C source/header files to disk and is a developer actionplugins enableandplugins disable, which write user plugin configuration- the active UDS workflows
uds subservices,uds ecu-reset,uds tester-present,uds security-seed,uds dump-dids,uds read-memory, anduds auto— they transmit invasive diagnostic requests (ECU reset, seed collection, DID/memory extraction, ranged enumeration, multi-id recon) and stay CLI-only operator actions behind the active-transmit gate. The referenceuds servicescatalog stays exposed; its active-probe mode only activates when a CLI caller supplies an interface on the command line. A configured[transport].default_interfaceorCANARCHY_DEFAULT_INTERFACEnever promotes it to probing, so MCPuds_servicesis reference-only on any machine regardless of local configuration (#530) - the active
xcp infoandxcp dumpworkflows — they connect to an XCP slave and read its capabilities / a bounded memory range, so they stay CLI-only operator actions behind the active-transmit gate (the broadcastxcp scanstays exposed) fuzz identify, a stateful multi-round human-in-the-loop replay/narrowing workflow (one bisected window replayed per invocation); CLI-only operator action
The TUI is for human inspection, not agent automation. Alt+1–Alt+5 switch the responsive Traffic, Signals, J1939, UDS, and Findings workspaces. Traffic defaults to a typed per-bus identifier summary; v switches to the chronological event log, F4 freezes inspection or returns live, and Enter drills into a selected row on narrow terminals. /filter traffic accepts the CLI filter atoms id==, pgn==, and sa== (J1939 source address, extended frames only), while plain text still performs substring filtering; invalid typed filters and unknown sort fields are reported. The sa== atom also works in non-interactive canarchy filter with unchanged output schemas. The TUI command entry uses the shared CLI executor; non-event results and errors appear in a read-only result view (F2 switches back to the workspaces, Esc closes the result). Agents should use CLI JSON or MCP tools for machine-readable results.
DBC decode results populate Traffic from decoded_message embedded frames and correlated signals. Active Traffic filters also constrain live inspector follow; F4 returns from historical inspection to the newest visible log event.
The authoritative CLI-to-MCP coverage matrix (exposed / excluded / deferred, with rationale) lives in docs/design/mcp-server.md; a test guard (test_every_cli_command_is_exposed_or_documented) fails the build if a new command drifts out of coverage.
For dataset workflows, agents should prefer MCP dataset tools when available. datasets_search and datasets_inspect include stable machine fields: ref, is_replayable, is_index, default_replay_file, download_url_available, and source_type. datasets_fetch distinguishes curated indexes from normal dataset entries with is_index, index_instructions, and download_instructions, and reports data_is_local: true when the fetch materialised real bytes into the cache rather than recording provenance for a remote file. When data_is_local is true, next_steps names the local-file commands to run against cache_path — datasets download and datasets replay do not apply and will fail with DATASET_REPLAY_UNAVAILABLE. Use datasets_replay_plan for safe replay preflight; use CLI datasets replay --list-files --json to choose a replay file and --file <id-or-name> to select it. Use max_frames or max_seconds to bound replay. For catalog:comma-car-segments, pass --platform <name> and --limit <n> when listing files so dynamic HuggingFace manifests remain bounded. Use CLI datasets stream --max-frames <n> to bound local downloaded dataset-file streaming. --chunk-size controls JSONL provenance chunk metadata only; it is not a frame limit. comma-rlog streaming requires optional openpilot LogReader support (uv pip install git+https://github.com/commaai/openpilot.git on Python 3.12.x) and returns COMMA_RLOG_SUPPORT_UNAVAILABLE when unavailable. Actual frame streaming remains CLI-only. Curated index entries that cannot be replayed return DATASET_INDEX_NOT_REPLAYABLE.
Every dataset in the catalog provider downloads from a host (zenodo.org, figshare.com, huggingface.co, ocslab.hksecurity.net) that a typical sandboxed agent environment blocks, so datasets fetch followed by a replay fails there with a transport error. When there is no egress, use the offline provider instead: datasets search --provider offline --json lists synthetic datasets that generate locally and need no network. datasets fetch offline:<name> writes real data into the cache and returns its path in cache_path, after which the local-file commands (datasets convert, datasets stream, capture-info, stats, j1939 summary, replay --file) work normally. Offline datasets carry synthetic: true in the machine fields, a licence string identifying them as synthetic, and a SYNTHETIC: description prefix. The data has real protocol structure but is not vehicle behaviour: use it to exercise tooling, never report analysis of it as a research finding. Current offline datasets are can-basic (candump, with a discoverable counter), j1939-basic (candump, with BAM/TP and a DM1 active fault), can-intrusion (hcrl-csv, attack-labelled), and signal-decoded (decoded-signal-csv).
A bare dataset ref (no provider: prefix) resolves against providers in order, and datasets_provider_list / datasets provider list --json reports that effective order as search_order plus a per-provider order index. The default is catalog before offline, so a bare ref prefers a real dataset over synthetic data of the same name; an operator can reorder it with [datasets].search_order in ~/.canarchy/config.toml. Prefer a prefixed ref (catalog:road, offline:can-basic) when the provider matters. A provider name in that config that does not exist fails every datasets command with DATASET_PROVIDER_NOT_FOUND (exit 1); a malformed value fails with DATASET_SEARCH_ORDER_INVALID.
Skills Workflow¶
CANarchy skills are phase-1 workflow descriptors, not MCP tools. Agents should discover and fetch skills through the CLI provider workflow, inspect the cached manifest and entry file, then run the referenced CANarchy commands explicitly through either the CLI or the MCP tools that already exist.
Recommended flow:
- Run
canarchy skills search <domain-or-task> --json. - Select a provider-qualified reference such as
github:j1939_compare_triage. - Run
canarchy skills fetch <provider>:<skill> --json. - Read
local_manifest_pathandlocal_entry_pathfrom the fetch result. - Check
compatibility,required_tools,inputs,outputs,skill.tags, andskill.domainsbefore applying the workflow. - Run required CANarchy commands explicitly and record the selected skill reference plus provenance in the final analysis.
Example:
canarchy skills search j1939 --provider github --json
canarchy skills fetch github:j1939_compare_triage --json
canarchy j1939 summary --file baseline.candump --json
canarchy j1939 compare --file baseline.candump --file after-start.candump --json
If MCP is available, agents may use MCP for commands that are already exposed as tools, such as j1939_summary. The skill itself is still selected and fetched through the CLI in phase 1, and compatibility.mcp=false means the agent should not assume MCP invocation is supported for the skill workflow.
Research Record Workflow¶
A session is the durable record of an analysis: what it consumed, what it produced, and whether that still holds. Agents that report a finding should record it so a human can check the finding later against the exact bytes it came from.
Recommended flow:
session_savewith the capture and DBC under analysis. The record stores a SHA-256 hash, size, and modification time per input, the effective configuration, and the CANarchy version.- Run the analysis tools as usual, writing the result to a file.
session_attachthat file withcommandset to the exact command that produced it andderived_fromset to the input ids from step 1, so the artifact points at the inputs it came from. Passembed: trueto keep the result inside the record.session_annotatewith the interpretation, targeting the input or artifact it refers to.session_verifybefore relying on an earlier record. It re-hashes everything offline and returnsverification.status, per-entryunchanged/changed/missing/unverifiable, areproduce_commandper recorded invocation, andrequired_actions. A degraded verification returnsok: falsewith codeSESSION_VERIFICATION_FAILED— the recorded conclusion no longer follows from the files on disk, so re-run the analysis rather than repeating the old finding.session_bundleto hand the whole record — manifest plus copies of its files — to another machine, andsession_importto open it there.
session_verify and session_load only read files: they never re-run a recorded command or touch the bus. A record saved before provenance existed reports provenance_available: false with a SESSION_PROVENANCE_UNAVAILABLE warning; re-run session_save with its inputs to upgrade it. Credentials are never recorded — omitted configuration keys are listed in effective_config.redacted_keys.
Response Format¶
Every tool returns a single JSON text block with the canonical result envelope:
{
"ok": true,
"command": "<command>",
"data": { "events": [...] },
"warnings": [],
"errors": []
}
Failures set "ok": false and populate errors with structured objects (code, message, hint), using the same error codes as the CLI JSON output.
For UDS workflows, uds_transaction events may include payload.complete=false when a multi-frame ISO-TP response was only partially captured or arrived out of order. In that case payload.response_data still contains the partial bytes that were reassembled.
When the optional Scapy extra is installed, UDS results may also report data.protocol_decoder="scapy" and include summary-level request_summary / response_summary enrichment on uds_transaction payloads while preserving the same result envelope and event type.
Example Interactions¶
tool: uds_services {}
→ {"ok": true, "command": "uds services", "data": {"service_count": 26, ...}}
tool: j1939_spn {"spn": 190, "file": "trace.candump"}
→ {"ok": true, "command": "j1939 spn", "data": {"mode": "passive", "observations": [...]}}
tool: j1939_spn {"spn": 190} # no file → built-in reference lookup
→ {"ok": true, "command": "j1939 spn", "data": {"mode": "reference", "name": "Engine Speed", "pgn": 61444, "units": "rpm", ...}}
tool: send {"interface": "vcan0", "frame_id": "0x7DF", "data": "0201F1", "ack_active": true}
→ {"ok": true, "command": "send", "data": {"frame": {...}, "mode": "dry_run"}}
Notes¶
- 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 0keeps 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. - MCP tool results set
isError=truewhenever the canonical JSON envelope hasok=false, including command failures, excluded targets, missing active-transmit acknowledgement, and isolated unexpected exceptions. Codes, messages, and hints remain in the JSON text. Successful calls setisError=false. SDK input-schema validation runs before the command handler: missing required fields or invalid schema types returnisError=truewith SDK validation text rather than a CANarchy JSON envelope. Correct the input and retry; ordinary errors leave the session available for later calls. - MCP streaming is not supported in v1 — live-capture tools (
capture, livegatewaywithdry_run=false) return a buffered batch from the active backend. Use CLIdatasets stream --max-frames <n>for bounded local dataset-file JSONL or candump pipelines, anddatasets replay --max-frames <n>or--max-seconds <s>for bounded remote dataset-ref or URL playback to stdout. shell,tui,mcp serve, andmcp installare not exposed as MCP tools.- Error codes are identical to the CLI, so existing JSON-parsing logic transfers without changes.
- Every canonical CANarchy JSON tool envelope is bounded (default 512 kB of final JSON text including metadata, configurable via
CANARCHY_MCP_MAX_RESPONSE_BYTES, minimum 1024 bytes; smaller positive settings fail before server startup). SDK-generated schema-validation and protocol errors are outside this cap. Oversized list data is trimmed and marked withdata.truncated: trueplus adata.truncationblock recording each surviving trimmed list'stotal_itemsvsreturned_items— check that marker before treating a short list as a complete result, and re-run via the CLI (or bound the input withmax_frames/seconds) when you need the full output. An unexpected in-tool failure returns aTOOL_EXECUTION_ERRORenvelope; the session and the other tools stay usable. encode(andsend --dbc) resolve message names by exact DBC name, case/spacing-insensitive match, or SAE PGN label (EEC1), and signal names by exact name, case/spacing-insensitive match, or SAE SPN name (Engine Speed) — so names displayed by decode tools re-encode directly. Unsupplied signals are defaulted and reported underdata.resolution.filled_signalswith a warning; review them before transmitting.- CLI capture paths: the
re *family andj1939 compareaccept both positional paths and--file <path>flags, so agents shelling out do not need to remember which convention a command uses. Filter expressions accept decimal,0x-prefixed hex, or bare hex IDs/PGNs with whitespace tolerated around operators. - RE tool results (
re_signals,re_counters,re_entropy,re_anomalies,re_corpus) annotate J1939 frames withpgn,pgn_label,source_address, andsource_address_name, and label or exclude J1939 transport-protocol framing (j1939_transport,excluded_transport_ids).re_anomalieswithout abaselinereports sparse ids underlow_rate_idsinstead of ranking them and caps z-scores at ±100σ — prefer supplying a known-goodbaselinecapture. - Reference-DBC matching in
re suggestuses 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. re_suggestproposes signal names for ranked candidates using offline heuristics only (reference-DBC overlap, the J1939 SPN/PGN catalog, and behaviour templates); each suggestion carries asourceandconfidence. The optional external-LLM enrichment (re suggest --llm <provider>) is CLI-only — it is not reachable through the MCP tool — because it sends candidate metadata to an external service and requires explicit operator confirmation. Even on the CLI it sends only candidate metadata (ids, bit ranges, observed ranges, heuristic names), never raw payload bytes, and records anexternal_enrichmentnote plus anEXTERNAL_SERVICE_CALLEDwarning.- Stdin pipelines:
capture-info,stats, andfilter --file -read candump text from stdin.filter --stdin,decode --stdin, andj1939 decode --stdinread JSONL FrameEvents from stdin regardless of output format. This enables pipingdatasets replaycandump output directly into analysis commands without temporary files. - Stdin pipelines are CLI-only. Over MCP, stdin carries the JSON-RPC transport, so passing
-to any file or source parameter (file,files,dbc,capture,baseline,reference,reference_dbc,source,artifact,artifacts,bundle,corpus) is refused before the command runs, with error codeSTDIN_MCP_EXCLUDEDand the MCP failure flag set. Pass a real file path instead: if the data is coming from a pipeline, write it to a file first (for examplecanarchy datasets replay offline:can-basic > /tmp/run.candump) and call the tool with that path. The parameter descriptions returned bylist_toolsstate the restriction.