ARCHITECTURE

A short, inspectable local pipeline

A standard Python package reads local files, normalizes records, aggregates them, and renders terminal or HTML output.

Overview

Local logs
JSON / JSONL
readers
normalized records
aggregate
range and periods
reporters
terminal / HTML
./out
local artifacts

Package layout

PathResponsibility
src/tokens_cli/cli.pyArgument validation, runtime configuration, range routing, diagnostics.
config.pySource paths, system timezone, output and platform cache locations, aliases.
doctor.pyMetadata-only environment diagnostics.
readers.pySafe file scanning, source parsers, normalized records, file cache.
aggregate.pyDate filtering and day/week/month summaries.
dashboard_payload.pySingle-pass dashboard aggregates, pseudonyms, replay and provenance data.
dashboard_wire.pyVersioned compact dashboard payload encoding.
live_dashboard.pyLoopback-only HTTP service, safe file-signature checks, ETag snapshots, and refresh synchronization.
report_*.pyTerminal, static HTML, and dashboard rendering.
dashboard_assets/Packaged HTML, CSS, and vanilla JavaScript assets.

Data flow

  1. Configure: choose sources, timezone, output, range, and cache behavior.
  2. Scan safely: reject symlinks, non-regular files, oversized files, and oversized JSONL lines.
  3. Normalize: preserve each source total while mapping common fields.
  4. Aggregate: calculate period, model, source, project, session, and composition views.
  5. Pseudonymize when requested: replace identifiers before dashboard entities enter the serialized payload.
  6. Render: print ANSI output, write a local HTML artifact, or serve the dashboard on loopback.
  7. Refresh live views: compare safe file signatures, reuse unchanged parsed records, and publish a new ETag snapshot only when report data changes.

Operational boundaries

Adding a source

Add a path and parser that returns the normalized record fields, register it in readers.SOURCES, expose it through CLI choices, document source accounting, and add parser, cache, aggregate, privacy, and packaging tests.

Keep the semantic boundaryA new source must not pretend missing project/session data is zero, and display code must not infer entity relationships that the source does not provide.