For agents
Use execution records you already have to get an evidence-backed cost answer.
nemulai explain runs the same accounting as nemulai.com/explain on files on disk and prints structured JSON with evidence ids. Local, offline, no account. Built so a coding agent with authorized access to a team's records can answer four questions without a browser.
When it is useful
- A customer's or workflow's agent cost went up and you want to know whether it was more tasks, more attempts per task, more calls per attempt, or pricier calls.
- You need the tasks that carry the most cost or the most retries, with the run ids, before you open anything else.
- You want to know what your records cannot show yet (unpriced calls, unmapped outcome labels, missing retry links) before someone reads a number as a fact.
Not useful for: finding causes (it does not infer them), deciding whether an agent is stuck (a task with many retries is reported as a task with many retries), or arbitrary trace formats (see inputs).
Supported inputs
Two CSV files, or a workspace file exported from the results page. Column names that differ are handled with a mapping profile; fields that are not in the export cannot be reconstructed.
runs.csv
- run_id *
- started_at *
- customer_id
- task_id
- parent_run_id
- relationship
- workflow
- workflow_version
- outcome
calls.csv
- run_id *
- model
- input_tokens
- output_tokens
- cached_input_tokens
- cost_usd
- call_id
- occurred_at
- provider
- status
plus either cost_usd, or model + input_tokens + output_tokens
Column reference, descriptions and templates: nemulai.com/explain#format. Without relationship attempts per task cannot be measured; without outcome nothing is a success; without cost_usd money is estimated from tokens at dated list prices and labelled as such.
Install
The published npm package nemulai (0.3.2) predates this command. Until 0.3.4 or later is released, run the CLI from a checkout of the repository:
git clone <repository> nemulai && cd nemulai npm ci && node packages/cli/build.mjs node packages/cli/dist/nemulai.js explain # prints the options
Requires Node 20+. No other prerequisite. When the release is published, npm i -g nemulai replaces the clone; check npm view nemulai version.
Complete example
# from a checkout of the repository (npm release pending; see "Install") node packages/cli/dist/nemulai.js explain \ --runs exports/runs.csv --calls exports/calls.csv \ --profile exports/nemulai-profile.json \ --customer acct-northgate --period 2026-08 --prior 2026-07 \ --json --out /tmp/explain.json
Structured response (abridged; numbers from the synthetic Ledgerline fixture in tests/fixtures/explain):
{
"format": "nemulai-explain-result",
"version": 1,
"scope": { "customer_id": "acct-northgate", "period": "2026-08", "prior": "2026-07" },
"current": { "tasks": 690, "attempts": 805, "calls": 1978, "unpricedCalls": 368,
"totalMicros": 49688466, "total_usd": 49.688466,
"measuredMicros": 11559405, "estimatedMicros": 38129061,
"outcomes": { "success": 511, "failure": 94, "abandoned": 74, "unknown": 11 },
"costPerSuccessMicros": 97238, "successRateKnownBp": 7526 },
"change": { "comparable": true, "totalDeltaMicros": 15634148, "total_delta_usd": 15.634148,
"volume": { "label": "Volume: more or fewer tasks", "micros": 11133100, "supported": true },
"unit": { "label": "Cost per task", "micros": 4501048, "supported": true },
"unitSplit": [
{ "label": "More or fewer attempts per task (retries)", "micros": 5113000, "supported": true },
{ "label": "More or fewer calls per attempt", "micros": 10165900, "supported": true },
{ "label": "Cost per call (tokens per call and price per token)", "micros": -10777800, "supported": true } ] },
"contributors": {
"by_version": [ { "key": "v4", "tasks": 368, "costMicros": 28351000 }, { "key": "v3", "tasks": 322, "costMicros": 21337400 } ],
"most_expensive_tasks": [ { "task_key": "root:run-01591", "root_run_id": "run-01591", "run_ids": ["run-01591", "run-01592"],
"attempts": 2, "retries": 1, "outcome": "success", "total_usd": 0.1406, "unpriced_calls": 1 } ] },
"investigate": { "most_retried_tasks": [ "…" ], "note": "Lists, not verdicts. Every entry carries its task key and run ids so the underlying records can be inspected." },
"missing_evidence": [ "368 of 1978 calls in 2026-08 are unpriced (368 × no list price for o4-policy-preview); the total is a lower bound." ],
"limitations": [ "Descriptive accounting of supplied records. It does not identify causes; a task with many retries is a task with many retries." ]
}Agent usage guide
- Run with
--json --out. If exit code is 1, print the message: it names the missing column, the detected header, or the unknown period/customer. - Read
missing_evidencefirst. Quote it; do not fill the gap. - Answer "what changed" from
change; each effect hassupportedand anote. - Answer "where to look" from
contributors.most_expensive_tasksandinvestigate.most_retried_tasks; citetask_keyandrun_ids, which exist in the runs file. - Never turn a cost pattern into a cause. The result is descriptive; say so.
- Save the mapping with
--save-profileso the next export with the same header needs no flags. The profile is checked against each new header before use.
Full contract: docs/wiki/explain-cli.md. Claude Code walkthrough: docs/wiki/agent-integration-claude-code.md. To test a workflow change on comparable tasks, see nemulai eval-compare (docs/wiki/eval-compare.md).
Schemas
- Input: two CSVs as above (column reference is the contract);
nemulai-explain-workspacev1 (results-page export). - Mapping profile:
nemulai-explain-mapping-profilev1. - Output:
nemulai-explain-resultv1;nemulai-eval-comparisonv1 for eval-compare.
Versions are literal fields in every file; a future incompatible change bumps the number and the CLI refuses versions it does not know.
Data handling
The CLI reads the files you name and writes to stdout and the files you name. The analysis code has no network calls; it is the same code the browser page runs client-side. Record cells are data, never executed or interpreted as instructions. The browser page at /explain keeps records in the tab unless you tick "remember in this browser". There is no hosted analysis API and no MCP endpoint yet; if one ships it will be opt-in and documented here.
Getting a small sample from your own system
Export one recent full calendar month and the month before, for one customer or workflow: a runs file with an id, a start timestamp and whatever you have of customer id, parent run id, retry/subagent relationship, workflow, version and outcome label; a calls file with the run id and either recorded cost or model plus token counts. Ids and labels only; no prompts, documents or personal names. A few thousand rows is plenty. Run nemulai explain; if it fails on column names it prints the detected header, and a profile fixes it.
Publishing this page does not make agents find it. A developer installs the CLI and mentions it to their agent; the walkthrough above shows how.