Skip to content

Share report

--share writes one HTML file that holds the data and the code to explore it: no server, no network, no other files. Interactive report covers what you can do in the page; this page covers how the file is built, in src/cli/build-share-report-data.ts and src/share-report/.

From --share to a self-contained HTML reportA command run with --share first builds its normal report. It then reads the events a second time, starting seven days earlier so 5-hour blocks can be placed and without syncing other machines, and prices them in every cost mode. The payload holds a cube of token, event, active-time and cost totals by period, source, model, project and machine; up to 200 newest sessions per project; 5-hour blocks per source; and the command's own JSON output. Project labels never hold a home path, and --redact numbers projects and machines. The payload and the client script are inlined into one HTML file whose content security policy blocks all network requests; it is written to the current directory and opened unless --no-open is passed. In the browser the client rolls the cube up by hour, day, week or month and recomputes charts and tables as filters change.llm-usage daily --sharebuilds the report as usualsecond readSame options, since moved back 7 daysfor blocks; no machine syncpriced in every cost mode at oncepayloadno home paths; --redactcubetotals by 5 dimensionssessions200 newest per projectblocks5-hour blocks per sourceenvelopethe command’s --jsonone HTML fileinline payload + client; CSP blocks networkwritten to ./, opened unless --no-openin the browserroll up by hour, day, week or monthfilters, charts, tables; view kept in the URL

summary, daily, weekly, monthly, compare, trends, efficiency, optimize, and wrapped accept --share, with --no-open and --redact. The file goes to the current directory under a fixed name per command (for example usage-daily-share.html, compare-share.html, llm-usage-wrapped-<year>.html) and replaces a file of that name: the old entry is unlinked and the new file created with mode 0600, so a symlink at that name is never followed. --no-open and --redact without --share are errors.

The command still prints its normal report to stdout. Before it does, it writes the file, logs Wrote <report> share report: <path> to stderr, and opens it with the system handler (xdg-open, open, or rundll32 on Windows) unless --no-open is passed. A file that cannot be opened is a warning, not a failure.

The page needs more than the command’s own rows: every event in the window, so the browser can regroup them. After building the report, the command reads the events again through buildUsageEventDataset, with the same options and three changes:

  • since moves back 7 days, so 5-hour blocks that started before the window are placed correctly;
  • until is the command’s resolved window end;
  • machine sync is off, so other machines are read from their caches as the first read left them.

Pricing loads once and prices every event in each cost mode (explicit, estimated, both), so the page can switch modes. When pricing cannot load, the estimated modes are dropped with a warning and listed in the payload as unavailable. --no-cost embeds no costs.

The payload has schemaVersion: 1 and report: 'share'; schema/report-share.v1.schema.json describes it. Its data holds:

  • meta: the command, time zone, window, initial view, cost mode, the filters in use (the --repo value itself is never embedded), and whether names are redacted.
  • dictionaries: the periods, sources, models, projects, and machines that the other parts index into.
  • cube: one cell per period, source, model, project, and machine, stored as columns. Each cell holds the token buckets, event count, active time, and the cost in each mode with a count of events missing a price. Periods are hours; when the hourly cube would make the file too large, cells more than 90 days before the window end roll up to days.
  • sessions: up to the 200 newest sessions per project, with tokens, cost, active time, and models. A session is labeled source · date time, never by its session id. Older sessions are counted, not listed.
  • blocks: estimated 5-hour blocks per source, across machines.
  • envelope: for summary, compare, trends, efficiency, optimize, and wrapped, the command’s own --json output, so the page can show the command’s panel.

Active time is the gaps between consecutive events in a session, each capped at 5 minutes, credited to the later event’s cell.

Project labels never hold a full home path, even without --redact: a home directory collapses to ~, and labels that only a full path would tell apart get #2, #3. A model name that looks like a path keeps only its last part. The envelope drops path fields (repoRoot, cwd, filePath and others) and scrubs paths from other strings.

--redact replaces project names with project-N and machine names with machine-N, numbered by total tokens. (unattributed) and local stay as they are. Models whose name holds a path or that LiteLLM does not list get model-N; to tell which, prices load even with --no-cost, and when they do not load every model gets model-N. The time zone and session start and end times stay. The same maps scrub the run’s stderr lines (ShareArtifact.scrubLog, applied through the logger): names become their stand-ins and paths <path>, except the Wrote … share report line. The page’s own “hide names” switch only masks the display; the file still holds the names.

renderShareHtml writes one document: a content security policy, an inline stylesheet, the payload as a JSON <script> block, and the client as an inline script. The policy is

default-src 'none'; script-src '<sha256>'; style-src '<sha256>'; img-src blob:; base-uri 'none'; form-action 'none'

so the page can run only its own script and style and cannot load or send anything. The payload is escaped for a script context. The client is built from src/share-report/client/ by scripts/build-share-client.mjs (esbuild, minified) into client-bundle.generated.ts, which the CLI build includes.

The file aims to stay under 8 MB. Past that, the CLI only warns and suggests a shorter window or narrower filters.

The client decodes the payload, then does all grouping itself:

  • rolls the cube up by hour (where hourly detail exists), day, ISO week, or month;
  • filters by date range, source, model, project, and machine (blocks ignore the model, project, and machine filters);
  • draws cost and tokens over time, projects, model mix, cache hit rate, cost per active hour, an hour-by-weekday heatmap, and 5-hour blocks, and lists projects with their sessions;
  • keeps the view in the URL hash, so a link reopens the same view, and “Save this view” writes a copy of the file that opens on it;
  • exports charts as SVG or PNG.