--- name: dimo description: This skill should be used when the user asks to "connect my DIMO vehicle", "query my vehicle data", "get vehicle telemetry", "check my car's battery", "see my vehicle signals", "show my car stats", "use DIMO", "query DIMO", or invokes /dimo. Guides users from zero to querying live telemetry from a DIMO-connected vehicle — covering developer onboarding, JWT exchange, and real-time signal queries. version: 0.1.0 argument-hint: "[developer-jwt] [token-id]" allowed-tools: Bash, mcp__Claude_Preview__preview_start, mcp__Claude_Preview__preview_eval, mcp__Claude_Preview__preview_list --- # DIMO Vehicle Data Guide users from zero to querying live data from their DIMO-connected vehicle. **Core principle:** The user should never need to touch the terminal. Use the preview tool to show forms and results, and run all API calls via Bash. **Data principle:** All vehicle data queries go through the DIMO Telemetry MCP endpoint (`POST https://telemetry-api.dimo.zone/mcp`) using the 10 defined MCP tools. Never write raw GraphQL or invent query structures. Consult `references/mcp-tools.md` for the full tool list, parameters, and curl format. Consult `references/signal-reference.md` for signal names and units when rendering results. --- ## Startup: Render the preview immediately Call `preview_list` first. If a DIMO preview is already running, skip `preview_start` entirely — do not re-render, it wipes all JS state and the displayed JWT. Only call `preview_start` with the HTML below if no preview exists. This is the first action before any text output or questions. ```html
Initialising
Vehicle
Access.

Exchange your Developer JWT for a vehicle-scoped token.

VALUES STAY LOCAL — USED ONLY TO CALL THE DIMO TOKEN EXCHANGE API.

``` Once `preview_start` returns, run Phase 0 routing. --- ## Phase 0: Routing **First, check whether the user already supplied a Developer JWT and a Token ID** (e.g. pasted a JWT string and/or a numeric Token ID in their message). If both are present, skip all questions and go straight to Phase 2 — pre-fill the preview form via `preview_eval` and trigger the exchange. The routing questions exist only to gather what the user hasn't already provided. If credentials are missing, ask these questions in sequence in chat. Stop at the first "No": 1. **"Do you have a DIMO Developer License and a Developer JWT from the Developer Console?"** - No → **Phase 1** (full onboarding) 2. **"Have you shared your vehicle with your developer app and noted your vehicle's Token ID?"** - No → **Phase 1, Step 5** (vehicle sharing only — skip steps 1–4) 3. Both yes → **Phase 2** --- ## Phase 1: Onboarding *Prose only — all steps happen in the DIMO Developer Console UI.* **Step 1 — Sign in** Go to [https://console.dimo.org](https://console.dimo.org) and sign in or create an account. **Step 2 — Obtain a Developer License** Follow the console prompts to apply for and activate a Developer License. **Step 3 — Create an app and set a redirect URI** Create a new application. Set the redirect URI to `http://localhost:3000/callback`. The console auto-generates a **Developer JWT** on save. **Step 4 — Copy your Developer JWT** Copy the Developer JWT and store it safely (e.g. a `.env` file or password manager). **Step 5 — Share your vehicle** Ask for the user's **Client ID** (shown next to the app in the console — looks like `0xabc123...`). Construct and display this URL as a clickable link: ``` https://login.dimo.org?clientId=&redirectUri=http%3A%2F%2Flocalhost%3A3000%2Fcallback&entryState=VEHICLE_MANAGER&permissions=11111111 ``` Display this message: *"Click this link, sign in with your DIMO account, share the vehicle(s), and note the Token ID shown for each vehicle — you'll need it next."* → Once the user has the Token ID, continue to Phase 2. --- ## Phase 2: Vehicle JWT Exchange The Developer JWT identifies the developer app but does not grant vehicle data access. Exchange it for a **Vehicle JWT** scoped to a specific vehicle token ID. > ⚠️ The Vehicle JWT expires in ~10 minutes. Re-run this exchange any time a query returns 401. **Step 1 — The preview form** The preview was rendered at startup. Never re-render it from scratch. If the user pre-supplied both credentials, pre-fill the form and trigger the button via `preview_eval`: ```javascript document.getElementById('devJwt').value = ''; document.getElementById('tokenId').value = ''; document.getElementById('submitBtn').click(); ``` Otherwise tell the user: *"Fill in your Developer JWT and Token ID, click **Get Vehicle JWT**, then send me any message."* **Step 2 — Read credentials and run the exchange via Bash** The preview sandbox blocks external HTTP — the button captures credentials in `window.__dimoFormData` but makes no network calls. Once the user responds, read the values: ```javascript window.__dimoFormData ``` Then run the exchange via Bash: ```bash curl -s -X POST "https://token-exchange-api.dimo.zone/v1/tokens/exchange" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"nftContractAddress":"0xbA5738a18d83D41847dfFbDC6101d37C69c9B0cF","privileges":[1,2,3,4,5,6,7,8],"tokenId":}' ``` **Step 3 — Inject the result into the preview** On success, store the token in context and update the UI via `preview_eval` using safe DOM methods (no innerHTML): ```javascript (()=>{ const token=''; const tokenId=''; window.__dimoVehicleJwt=token; window.__dimoTokenId=tokenId; const r=document.getElementById('jwtResult'); while(r.firstChild)r.removeChild(r.firstChild); const card=document.createElement('div');card.className='result-card'; const lbl=document.createElement('p');lbl.className='result-label';lbl.textContent='VEHICLE JWT'; const st=document.createElement('p');st.className='result-status status-ok';st.textContent='VEHICLE JWT GENERATED — VALID FOR ~10 MINUTES'; const ta=document.createElement('textarea');ta.className='result-jwt';ta.readOnly=true;ta.value=token;ta.rows=4; const cp=document.createElement('button');cp.className='btn-ghost';cp.textContent='COPY'; cp.addEventListener('click',()=>{navigator.clipboard.writeText(token);cp.textContent='COPIED';setTimeout(()=>cp.textContent='COPY',2000);}); card.append(lbl,st,ta,cp);r.appendChild(card); const btn=document.getElementById('submitBtn'); btn.textContent='REFRESH JWT';btn.disabled=false;btn.style.opacity='1'; const btnSig=document.getElementById('btn-signals'); btnSig.disabled=false; document.getElementById('pane-jwt').hidden=true; document.getElementById('pane-signals').hidden=false; document.getElementById('btn-jwt').classList.remove('active'); btnSig.classList.add('active'); })() ``` On error, surface the message in the preview: ```javascript (()=>{ const r=document.getElementById('jwtResult'); while(r.firstChild)r.removeChild(r.firstChild); const card=document.createElement('div');card.className='result-card'; const msg=document.createElement('p');msg.className='result-status status-err'; msg.textContent='ERROR: '; card.appendChild(msg);r.appendChild(card); const btn=document.getElementById('submitBtn'); btn.textContent='GET VEHICLE JWT';btn.disabled=false;btn.style.opacity='1'; })() ``` **Source of truth:** After a successful exchange, store `devJwt`, `tokenId`, and `vehicleJwt` explicitly in your context. `window.__dimoVehicleJwt` is a convenience cache only — never read the JWT back from the preview window. The preview can restart or refresh at any time, wiping all JS state. **Never ask the user to re-paste or re-fill the form** if credentials exist anywhere in the conversation context. ### Preview JS state loss (window vars gone, UI still visible) Do NOT call `preview_start` — the UI is still rendered. Just re-run the Bash exchange with credentials from context and inject the fresh token via `preview_eval`. ### Preview fully gone (preview_list shows nothing) 1. Call `preview_start` with the inline HTML template 2. Re-run the Bash exchange immediately using `devJwt` and `tokenId` from context 3. Inject the result via `preview_eval` — do not prompt the user for anything → Proceed to Phase 3. --- ## Phase 3: Vehicle Queries via MCP Before querying, confirm the Vehicle JWT is in your context. Do not read it from `window.__dimoVehicleJwt` — that variable is unreliable across preview refreshes. If it is missing from context, follow the restart recovery steps in Phase 2. All queries use the DIMO Telemetry MCP endpoint. See `references/mcp-tools.md` for the full tool reference, curl format, and parameter details. > ⚠️ If any query returns 401, the Vehicle JWT has expired. Re-run the Bash exchange silently using `devJwt` and `tokenId` already in context, then inject the new token into the preview via `preview_eval` and retry the query — do not ask the user to re-fill the form. **Never write raw GraphQL or invent query structures.** Use only the 10 defined MCP tools. If unsure of a tool's parameters, call `get_schema` (no JWT required) to introspect — see `references/mcp-tools.md`. ### Step 1 — Discover available signals Always start with `telemetry_get_available_signals` to see what this specific vehicle reports: ```bash curl -s -X POST "https://telemetry-api.dimo.zone/mcp" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"telemetry_get_available_signals","arguments":{"tokenId":}},"id":1}' ``` Render the returned signal list in `#signalsContent` as a `.signal-card`. Ask what signals to explore. ### Step 2 — Query with the right tool Select the tool based on the user's request (quick reference below). Full parameters in `references/mcp-tools.md`: | User wants | MCP tool | |---|---| | Latest readings | `telemetry_get_latest_signals` | | History / trend | `telemetry_get_signals_time_series` | | Point-in-time snapshot | `telemetry_get_signals_snapshot` | | Data coverage overview | `telemetry_get_data_summary` | | Trip history | `telemetry_get_trip_segments` | | Daily driving summary | `telemetry_get_daily_activity` | | Fault / event log | `telemetry_get_events` | | Verified attestations | `telemetry_get_attestations` | | VIN credential | `telemetry_get_vin_credential` | Only request signals the vehicle reported in `telemetry_get_available_signals`. Cross-reference signal names and units with `references/signal-reference.md` when rendering results. ### Step 3 — Render results Use `preview_eval` to **append** a new `.signal-card` to `#signalsContent` after each query — never replace existing cards. Include the tool name, query timestamp, and formatted signal values with units. --- ## Error Reference | Error | Fix | |---|---| | 401 on MCP query | Vehicle JWT expired — re-run Phase 2 | | 401 on token exchange | Developer JWT invalid — re-copy from console | | Signal not in result | Confirm via `telemetry_get_available_signals` — vehicle may not report it | | Token ID not recognized | Confirm vehicle is shared with the developer app in the console | | Tool parameter error | Call `get_schema` (no JWT) to introspect tool definitions | --- ## Additional Resources - **`references/mcp-tools.md`** — Full MCP tool list, parameters, curl format, and tool selection guide - **`references/signal-reference.md`** — All signal field names, units, and descriptions