| name | capture-reading |
| description | Take a reading from an OBD-II adapter and write it as a JSON snapshot, or log a drive as NDJSON. Use for "read the car", "scan for codes". |
| allowed-tools | Bash, Read, Write |
Capture an OBD-II reading
Connect to the adapter, read what the ECU offers, and write it to the workspace
in the schema at ${CLAUDE_PLUGIN_ROOT}/schemas/snapshot.schema.json.
Status: work in progress. ${CLAUDE_PLUGIN_ROOT}/scripts/obd_capture.py
is a stub that has never run against a car. Until it has, this skill's job is to
get a reading in by whatever route works — including a scan-tool app's export
or a photograph of a handheld reader — and normalise it into the schema. The
schema is the deliverable; the transport is an implementation detail.
Inputs
- Mode —
snapshot (default) or drive (continuous log).
- PID set — defaults to the core set in
${CLAUDE_PLUGIN_ROOT}/reference/pids.md. For drive, four or five PIDs
chosen for the question, because a clone adapter polls serially.
- Engine state — ask, do not infer.
off, key_on_engine_off, cranking,
running_cold, running_warm.
- Odometer — ask. Most vehicles do not expose it over generic OBD-II, and it
is what maintenance planning needs.
Steps
-
Locate the workspace. Confirm vehicle.json exists in the project
directory. If not, say so and offer new-workspace. Do not write readings
into an arbitrary directory.
-
Read the adapter config from ${WORKSPACE:obd-diagnostics}/adapter.json
if present — port, baud, transport. If absent, ask once and write it there so
the next run does not ask again. Machine-local, deliberately not in the
workspace repo.
-
Check the connection before reading. Report which of these is true:
adapter not found, adapter found but no vehicle response, vehicle connected.
The middle case is almost always ignition off, and it looks identical to a
broken adapter unless you name it.
-
Query PID support first (mode 01 PID 00/20/40…). Read only what is
supported; record the rest in unsupported_pids.
-
Read, in this order: status and readiness monitors → stored DTCs (mode
03) → pending DTCs (mode 07) → permanent DTCs (mode 0A) → freeze frame (mode
02) for each code → live PIDs (mode 01).
Get the freeze frame before anything that might disturb it. It is the
most diagnostically valuable data on the car and there is exactly one copy.
-
Never clear codes. Mode 04 is out of scope. See
${CLAUDE_PLUGIN_ROOT}/reference/dtc-codes.md for why.
-
Write the snapshot to readings/<ISO8601>.json, : stripped from the
filename. For a drive, write readings/<ISO8601>.ndjson plus the
.meta.json sidecar.
-
Validate before reporting success:
python3 ${CLAUDE_PLUGIN_ROOT}/scripts/validate.py readings/<the-new-file>.json
A snapshot that does not validate is a bug in the capture, not a quirk of the
car. Fix it before it lands in the repo — an invalid reading is worse than no
reading, because it will be trusted later.
-
Report what was found, and — importantly — what was not readable and
why. Then hand off: codes present → decode-dtcs; no codes but a symptom →
diagnose-fault.
Distinguishing "no fault" from "cannot see the fault"
Three different results read the same in a naive summary. Separate them:
- No codes, monitors complete — the emissions systems genuinely report clean.
- No codes, monitors incomplete — codes were recently cleared. This is not a
clean bill of health. Check
DISTANCE_SINCE_DTC_CLEAR and say so.
- No codes, but a warning light is on — the fault is very likely in a system
generic OBD-II does not expose (ABS, airbag, transmission, body). Say that the
light is unexplained by this tool, not that nothing is wrong.
Data storage
- Readings → the workspace repo,
readings/.
- Adapter connection settings →
${WORKSPACE:obd-diagnostics}/adapter.json,
machine-local, created on first run.
Notes
Do not run a capture while driving. A drive log is started before moving and
stopped after parking, or run by a passenger.