Skip to content

About

Privacy-conscious Codex dashboard for multi-machine usage, quotas, credits, API-equivalent costs, and GPT-6 Sol/Luna pricing.

Topics

Resources

Contributing

Stars

7 stars

Watchers

0 watching

Forks

Repository files navigation

Local Usage Dashboard icon

Local Usage Dashboard for Codex

Local Usage turns the Codex session metadata stored on your computer into a fast, privacy-conscious usage dashboard. It can run entirely on one machine, or several machines can send signed, minimized usage snapshots to an optional central dashboard hosted with OpenAI Sites or on your own server.

Stable release 1.5.5 · Docker image 1.5.5 · AGPL-3.0-or-later · Changelog · CI status

Setup guides: deploy the central dashboard with OpenAI Sites · deploy the public Mesh ingress · install a reporting agent

Donate

If you like this project and want to support its ongoing development, you can buy me a coffee. Donations are entirely optional; the dashboard remains free and open source.

What the application shows

  • API-equivalent cost using the observed Standard or Fast service tier, split between fresh input, cached input, and output;
  • estimated ChatGPT Codex credits, including the observed Fast-mode multiplier for each call;
  • projects, conversations, model calls, turns, duration, tokens, cache rate, and cost share;
  • hourly, daily, and monthly activity charts with click-to-zoom drill-down;
  • a transient Custom date range while drilling into a chart, applied to the rest of the page without overwriting the user's saved Custom range;
  • current and historical weekly quota periods, including the subscription tier observed during each period;
  • early or free-reset boundaries, hourly activity bars, cumulative quota consumption, and a projection to the end of the current quota period;
  • filters by project, model, period, usage, and conversation name.

The interface is available in French, English, German, Spanish, Italian, Portuguese, Japanese, Russian, and Simplified Chinese. The browser language is used on first visit when supported. Explicit language choices, date preferences, and custom pricing remain in browser storage.

Choose Settings → Appearance for the original green theme or the blue, violet and amber palettes. The choice applies immediately to the dashboard and its charts, persists in this browser and synchronizes across tabs on the same origin. Local and hosted dashboards share the same themes. See UI themes to add a palette.

The server indexes sessions incrementally and persists a derived snapshot. An open page checks for newer data every 15 seconds, while Refresh forces an immediate source check.

Deployment models

The same dashboard supports four complementary modes:

Mode Start it with Interface Data destination
Local GUI npm start, the launch scripts, or the dashboard Docker image Local web GUI on port 4317 This machine only
Local GUI + reporting agent Local GUI with MESH_HUB_URL configured Local and Centralized views Signed minimized snapshots are sent to the selected hub
Headless reporting agent npm run start:agent or the Docker agent target None; no HTTP port Signed minimized snapshots are sent to the selected hub
Central hub sites-hub/ on OpenAI Sites, or DASHBOARD_MODE=hub locally Aggregated web GUI and machine administration D1 on Sites, or the self-hosted hub store

The “agent” in this README is a collector and reporter belonging to this project. It is not an autonomous Codex AI agent: it cannot execute tasks, read arbitrary files, or receive commands from the hub.

flowchart LR
  subgraph A["Windows, macOS, or Linux machine"]
    LogsA["Local Codex session metadata"] --> CollectorA["Local collector"]
    CollectorA --> GuiA["Optional local GUI"]
  end
  subgraph B["Another machine"]
    LogsB["Local Codex session metadata"] --> CollectorB["Headless or GUI collector"]
  end
  CollectorA -->|"signed minimized snapshots"| Hub["OpenAI Sites or self-hosted hub"]
  CollectorB -->|"signed minimized snapshots"| Hub
  Hub --> Central["Centralized dashboard"]
Loading

Local mode is always the default. Nothing is sent to a hub unless MESH_HUB_URL is explicitly configured.

What is new on develop compared with main

  • a persistent Custom date-time range, including an unbounded Now end;
  • chart click drill-down that temporarily filters the entire page to the visible range;
  • current and navigable historical weekly quota periods, with observed plan tiers and correct early-reset boundaries;
  • responsive hourly historical charts and cumulative current-period quota projections;
  • Standard/Fast API-equivalent pricing and separate ChatGPT Codex credit calculations;
  • one deterministic browser bundle shared by local Node, Docker, and Sites deployments;
  • versioned /api/capabilities and /api/usage contracts across all runtimes;
  • an optional signed multi-machine Usage Mesh;
  • a reusable collector, a headless agent entrypoint, and a dedicated Docker target;
  • an authenticated OpenAI Sites hub backed by D1, with enrollment and node revocation.

Requirements

  • Node.js 22.13 or newer for the local dashboard/agent, or Docker;
  • a local Codex installation with session files under the Codex home directory;
  • Node.js 22.13 or newer when developing or testing sites-hub/ locally.

The root application has no npm runtime dependencies. Windows, macOS, and Linux are supported anywhere Node.js or Docker can access the user's Codex data directory.

Usage is stored relationally in embedded SQLite locally and in Docker, and D1 on Sites. No database server or SQL container is needed. Existing JSON caches are imported automatically without deleting the originals. See storage, migrations, backups and performance.

Quick start: local GUI only

Clone the repository:

git clone https://github.com/capisoft-lib/codex_usage.git
cd codex_usage

On Windows, double-click start-dashboard.cmd, or run:

.\start-dashboard.cmd

On macOS or Linux:

chmod +x start-dashboard.sh
./start-dashboard.sh

The equivalent direct command on every OS is:

npm start

Open http://127.0.0.1:4317. With no MESH_HUB_URL, the GUI stays local and does not start outbound reporting.

Direct mode reads only these paths under the current user's Codex directory:

~/.codex/sessions/
~/.codex/archived_sessions/
~/.codex/session_index.jsonl

It does not authenticate with OpenAI and never opens auth.json.

Optional mini quota window

In dashboard Settings, choose the five-hour quota, weekly quota, or both, then open the compact window. It uses the selected data source, language and palette. The browser popup does not guarantee always-on-top behavior.

For a native always-on-top window, install the separate desktop helper with Node.js 22.13 or newer:

npm ci --prefix desktop
npm run start:desktop

Electron is confined to desktop/; npm start, the existing platform launchers, Docker and the headless agent keep their dependency-free behavior. The Electron binary downloads on first launch if necessary.

The desktop helper opens the miniature immediately and respects HOST and PORT. It reuses a compatible dashboard already running at that address, or starts its own server. Closing the window keeps the tray menu available; Quit Codex Usage desktop stops only a server started by this helper. The application menu provides the same actions if the tray is unavailable.

To display quotas from an existing local server, Docker deployment or hosted Site, run the helper on your desktop computer with the dashboard URL:

npm run start:desktop -- --url https://your-dashboard.example/

This mode starts no local collector or server. The miniature is bundled locally; the remote deployment does not need to provide mini.html. An accessible dashboard API works directly. For a private Mesh hub, open Configure access, create a one-time association code in the site's administration (the same operation used for an agent), and enter the supplied hub address and code. Use the public Mesh ingress address supplied by the administration, which can differ from the dashboard URL. No OpenAI login runs inside Electron.

The helper stores its own Mesh identity in its operating-system user-data directory and reconnects on subsequent launches with the same dashboard URL. It only sends signed read requests, never collects or uploads sessions, and never shares the sending agent's identity. The current Mesh protocol grants the same node permissions as an agent; it does not issue a read-only credential. Revoke the Quota desktop node in the administration to withdraw access. The existing sending agent remains responsible for fresh observations.

When the helper starts the server, the dashboard Settings button opens the native window and passes its preferences. When reusing an independently started server, that button remains a browser popup; use the desktop menu to reopen the native window. Browser and Electron preferences live in separate storage, so existing native windows do not live-sync preferences from an external browser. Reopening through Settings passes the latest selection to a helper-owned server.

The miniature polls every 15 seconds and updates countdowns every second. It displays the last observation time separately from the last successful check, labels observations older than five minutes, and keeps the last values visibly marked on connection loss. Expired balances are not reused for a new quota window. A hosted dashboard selects its centralized source automatically.

Desktop validation: after npm run build:ui, run npm test --prefix desktop in a graphical desktop session (or under Xvfb on Linux). The smoke tests use isolated profiles and empty Codex directories. Windows CI runs them alongside the existing checks; screenshots are saved in the temporary directory printed by the test. Native behavior on macOS and Linux still requires platform-specific verification.

Docker

The dashboard image runs as a non-root user with all Linux capabilities removed. Only the three required Codex sources are mounted read-only; the .codex root and auth.json are never mounted. A named volume preserves the derived snapshot and, when enabled, the reporting agent's device identity.

Published dashboard image

The public Linux AMD64/ARM64 image is:

capitaine/codex-usage-dashboard:1.5.5

The 1.0.2 release is also mirrored at ghcr.io/capisoft-lib/codex-usage-dashboard:1.0.2.

On Windows PowerShell:

$codexData = Join-Path $env:USERPROFILE ".codex"
$image = "capitaine/codex-usage-dashboard:1.5.5"

docker pull $image
docker volume create codex-usage-dashboard-storage
docker run -d `
  --name codex-usage-dashboard `
  --restart unless-stopped `
  --init `
  --read-only `
  --security-opt no-new-privileges:true `
  --cap-drop ALL `
  --pids-limit 128 `
  -p 127.0.0.1:4317:4317 `
  --mount "type=bind,source=$codexData\sessions,target=/codex-data/sessions,readonly" `
  --mount "type=bind,source=$codexData\archived_sessions,target=/codex-data/archived_sessions,readonly" `
  --mount "type=bind,source=$codexData\session_index.jsonl,target=/codex-data/session_index.jsonl,readonly" `
  --mount "type=volume,source=codex-usage-dashboard-storage,target=/app-cache" `
  --tmpfs /tmp `
  $image

On macOS or Linux:

IMAGE="capitaine/codex-usage-dashboard:1.5.5"

docker pull "$IMAGE"
docker volume create codex-usage-dashboard-storage
docker run -d \
  --name codex-usage-dashboard \
  --restart unless-stopped \
  --init \
  --read-only \
  --security-opt no-new-privileges:true \
  --cap-drop ALL \
  --pids-limit 128 \
  -p 127.0.0.1:4317:4317 \
  --mount "type=bind,source=$HOME/.codex/sessions,target=/codex-data/sessions,readonly" \
  --mount "type=bind,source=$HOME/.codex/archived_sessions,target=/codex-data/archived_sessions,readonly" \
  --mount "type=bind,source=$HOME/.codex/session_index.jsonl,target=/codex-data/session_index.jsonl,readonly" \
  --mount "type=volume,source=codex-usage-dashboard-storage,target=/app-cache" \
  --tmpfs /tmp \
  "$IMAGE"

Then open http://127.0.0.1:4317.

docker logs -f codex-usage-dashboard
docker stop codex-usage-dashboard

Build from source with Compose

Copy .env.example to .env, then set CODEX_DATA_PATH to the absolute path of the local .codex directory.

Windows:

Copy-Item .env.example .env
# Set CODEX_DATA_PATH=C:/Users/your-name/.codex in .env
docker compose up -d --build

macOS or Linux:

cp .env.example .env
# Set CODEX_DATA_PATH=/home/your-name/.codex in .env
docker compose up -d --build

The following sources must exist before Compose starts:

$CODEX_DATA_PATH/sessions/
$CODEX_DATA_PATH/archived_sessions/
$CODEX_DATA_PATH/session_index.jsonl

Compose deliberately refuses to create missing host paths. docker compose down keeps the named storage volume; avoid docker compose down -v unless you intend to delete the cached analysis and agent identity.

Add a reporting agent to a machine

An agent can be added to any Windows, macOS, or Linux computer that runs Codex and can run Node.js or Docker. Each machine remains authoritative for its own logs: it analyzes locally, removes disallowed fields, signs the result with an Ed25519 key created on that machine, and pushes the minimized snapshot to the hub.

For a complete installation procedure, including Node.js and Docker operation, verification, updates, revocation, and recovery, read Install a reporting agent. Windows laptops should use the official Task Scheduler supervisor for sleep/resume recovery and automatic restart.

1. Create an association command

For a Sites hub, sign in with ChatGPT, open /admin, and select Add a machine. The page generates a ready-to-copy command containing the public ingress address and a code that expires after ten minutes and can be used once.

For a self-hosted hub, create the same code through its administration endpoint as described below.

2. Associate and start the machine

From the checked-out project folder on the new machine, run the command copied from /admin:

npm run start:agent -- --hub-url "https://your-mesh-ingress.example" --associate "AAAA-BBBB-CCCC-DDDD-EEEE-FFFF-0000-1111"

The first successful synchronization persists the non-secret ingress address and the machine's private Ed25519 identity in .cache/mesh-agent.json. Later starts need only npm run start:agent; neither the one-time code nor any shared infrastructure token remains configured.

Optional but recommended settings are:

MESH_NODE_ALIAS=Office PC
MESH_AGENT_STATE_PATH=.cache/mesh-agent.json
MESH_PROJECT_MODE=hash
MESH_INCLUDE_TITLES=false

For a private Sites hub, MESH_HUB_URL is the dedicated public Mesh ingress, not the private Site. Reporting machines never receive a Site bypass credential.

3. Choose GUI or headless operation

To run the local GUI and the reporting agent together:

npm start

Because the persistent association is present, the GUI exposes both Local and Centralized sources. The browser requests centralized data through its local server; the enrolled agent signs that read request and the hub returns only the current owner's aggregate.

To report without serving a GUI:

npm run start:agent

The headless process uses the same incremental collector but opens no HTTP port. The Dockerfile also exposes a dedicated target:

docker build --target agent -t codex-usage-agent .

Run it with the same three read-only Codex mounts, the /app-cache volume, and the MESH_* environment variables used by the dashboard container. Keep MESH_AGENT_STATE_PATH persistent: it contains the machine's private signing key and enrollment identity. Remove MESH_ENROLLMENT_CODE after the first successful enrollment.

OpenAI Sites as the central dashboard

OpenAI Sites can build, host, refine, and share web applications from ChatGPT. Sites is currently documented as a public beta; availability and limits depend on plan, region, and workspace settings. Site management happens in ChatGPT on the web or desktop, rather than from the standalone Codex CLI or IDE extension.

You do not install this Site inside Codex. Open this repository in the desktop app and give the deployment request directly to Codex in a conversation where Sites is available. Mentioning @Sites starts that workflow explicitly. ChatGPT on the web can then manage the existing Site; a web conversation can update source only when that source is available to it. The detailed procedure is in Deploy the central dashboard with OpenAI Sites.

For a first deployment or an update, give Codex this request first:

@Sites Prepare the Sites application in sites-hub/. If the ignored
sites-hub/.openai/hosting.json exists, reuse only that linked Site. Otherwise,
create a new private Site in my account with access limited to me. Never commit
the project ID or production URL. Run the relevant tests and build, then save a
new version without deploying it. Show me the result before changing access,
secrets, or production.

After reviewing the saved version, ask:

Deploy the approved saved version. Keep the current access policy, database
binding, and runtime settings unchanged, then give me the production URL and
deployment status.

Saving and deploying are deliberately separate: every Sites deployment URL is a production URL. If immediate publication is intended, Codex can perform both operations in one request, but the two-step prompt above is the safer default.

This repository's Sites application lives in sites-hub/. It provides:

  • the same generated dashboard UI as the local server and Docker image;
  • ChatGPT identity for browser visitors;
  • an /admin page for one-time enrollment codes, machine status, and revocation;
  • D1 storage for owners, enrollments, machines, sanitized snapshots, and quota history;
  • signed endpoints for enrollment, ingestion, and owner-scoped reads;
  • a separate stateless public ingress that keeps private-Site authorization server-side.

The repository contains no production project ID or private Site URL. Every user creates their own private Site, D1 database, ingress configuration, and server-side upstream secret. Do not share deployment files between users. This keeps deployments as separate data silos, while authenticated Mesh reads are also scoped to the owning Site user.

The local GUI and the Site are separate deployments, but both use the bundle generated from root public/. npm run build:ui writes a deterministic bundle and SHA-256 manifest under dist/dashboard/; a Sites build regenerates and copies that exact bundle. Do not edit generated dashboard copies.

Prepare and verify the Site

cd sites-hub
npm install
npm test
npm run lint

Run npm run db:generate only after changing the D1 schema, then review the generated migration before deployment. The committed sites-hub/.openai/hosting.example.json declares the DB binding shape. The ignored hosting.json links only the local checkout to that user's private Site and must never contain secrets.

Publish with Sites

Use the Sites workflow in ChatGPT desktop or web to open the existing project, save a version, and deploy it. The official documentation separates saving a version from deployment and notes that every deployment URL is a production URL, so verify the saved version before publishing.

In the Sites settings:

  1. bind the D1 database declared as DB and apply the checked-in migrations;
  2. configure any secret or environment value in Sites settings, not in .openai/hosting.json;
  3. keep access private and limited to the deploying user's account unless other trusted users are deliberately authorized;
  4. deploy mesh-ingress/ and store the Site bypass value only as its encrypted SITES_UPSTREAM_AUTH_TOKEN server-side secret;
  5. configure machines with the public ingress URL and a one-time enrollment code only.

After deployment, sign in to /admin, create a one-time code, enroll each machine, and use /dashboard/index.html for the aggregate. Keep Sites and reporting agents on compatible Mesh protocol versions when deploying schema or protocol changes.

Self-hosted central hub

Sites is optional. A local or private-network hub can use the same root server in hub mode.

Create a long random administrator token in a non-versioned environment and start it:

$env:MESH_ADMIN_TOKEN = '<long-random-secret>'
docker compose -f compose.mesh-hub.yaml up -d --build

Create a ten-minute enrollment code:

Invoke-RestMethod -Method Post -Uri http://127.0.0.1:4318/api/mesh/enrollments `
  -Headers @{ Authorization = "Bearer $env:MESH_ADMIN_TOKEN" }

Configure each machine with:

MESH_HUB_URL=http://private-hub-address:4318
MESH_ENROLLMENT_CODE=AAAA-BBBB-CCCC-DDDD-EEEE-FFFF-0000-1111

If the hub is reachable outside a trusted private network, place it behind HTTPS and protect its browser interface. Mesh requests remain protected by signatures, timestamps, monotonic sequence numbers, and node revocation.

Mesh privacy model

The default transmitted snapshot contains counters, tokens, models, timestamps, duration, state, a machine name or explicit alias, and minimized project identity. A canonical GitHub URL already present in session metadata may identify the same project across machines; credentials and query parameters are removed. Otherwise, the working path is hashed by default.

The agent never sends:

  • auth.json or any OpenAI/Codex credential;
  • raw JSONL logs;
  • prompts, responses, reasoning, tool output, or commands;
  • file contents, secrets, usernames, or full working paths in the default mode.

Additional guarantees:

  • MESH_PROJECT_MODE=hash is the default; basename and full are explicit, more revealing choices;
  • MESH_INCLUDE_TITLES=false removes conversation titles by default;
  • the hub is push-only and cannot browse the machine or request extra fields;
  • revoking a node immediately blocks future uploads and signed reads;
  • sequence numbers prevent replay and duplicate processing from the same node;
  • quota is account-level: the hub keeps the newest observation and never adds percentages from multiple machines.

Shared UI and API contract

public/ is the only editable browser UI source. The local server, dashboard container, self-hosted hub, and Sites adapter all implement the same versioned contract:

  • GET /api/capabilities describes runtime, available sources, default source, and refresh support;
  • GET /api/usage?source=local|centralized returns the public usage snapshot.

The browser maintains separate Local and Centralized caches. The local view is not replaced by enrolling a machine.

While the dashboard tab is visible, it checks for updated data every 15 seconds in both modes and refreshes immediately when you return to the tab. Failed requests retry automatically, including after a failed first load. This reads the latest available snapshot; source collection and Mesh synchronization still follow the agent's configured interval (REFRESH_INTERVAL_MS, 60 seconds by default).

Configuration

Variable Default Description
HOST 127.0.0.1 Interface used by the local HTTP server.
PORT 4317 Local dashboard port.
CODEX_HOME $HOME/.codex Codex data directory.
CODEX_SESSIONS_PATH $CODEX_HOME/sessions Explicit session directory, used by scoped Docker mode.
CODEX_ARCHIVED_SESSIONS_PATH $CODEX_HOME/archived_sessions Explicit archived-session directory.
CODEX_SESSION_INDEX_PATH $CODEX_HOME/session_index.jsonl Explicit conversation-title index.
REFRESH_INTERVAL_MS 60000 Source reindex interval in milliseconds, minimum 1000.
SNAPSHOT_PATH .cache/usage-snapshot.json Legacy import source; SQLite defaults to this path plus .sqlite. Empty uses in-memory SQLite unless USAGE_DATABASE_PATH is set.
USAGE_DATABASE_PATH ${SNAPSHOT_PATH}.sqlite Optional embedded SQLite path; use a persistent Docker volume.
MESH_HUB_PATH .cache/mesh-hub.json Legacy hub import source; SQLite defaults to this path plus .sqlite.
MESH_DATABASE_PATH ${MESH_HUB_PATH}.sqlite Optional embedded SQLite path for self-hosted hubs.
DASHBOARD_ASSETS_PATH dist/dashboard Generated UI bundle served locally.
DASHBOARD_MODE local local analyzes this machine; hub accepts and aggregates Mesh snapshots.
MESH_HUB_URL empty Enables the outbound reporting agent and Centralized source.
MESH_NODE_ALIAS system machine name Optional display-name override.
MESH_ENROLLMENT_CODE empty One-time code required only for initial enrollment.
MESH_AGENT_STATE_PATH .cache/mesh-agent.json Persistent enrollment identity and private key.
MESH_BATCH_SIZE 25 (100 in Compose) Maximum minimized sessions per request.
MESH_PROJECT_MODE hash Project privacy mode: hash, basename, or full.
MESH_INCLUDE_TITLES false Explicitly allow sanitized conversation titles.

Windows PowerShell example:

$env:PORT = "8080"
$env:CODEX_HOME = "D:\CodexData"
npm start

macOS/Linux example:

PORT=8080 CODEX_HOME=/path/to/.codex npm start

Pricing and weekly quota estimates

The dashboard derives two separate estimates from locally observed model calls. It does not require an API key or actual API billing data.

  • Codex credits use the published ChatGPT Codex rate card. Each call inherits its recorded service tier, and known Fast/Priority calls receive the documented credit multiplier.
  • API-equivalent cost estimates what the same calls would have cost through the API. Standard prices, published API Fast rates, and long-context adjustments are applied independently from ChatGPT credit multipliers.
  • Both estimates select the rate applicable at each call's original timestamp from a shared, versioned catalog. Later price cuts do not reduce earlier consumption; late imports retain their historical rate.
  • GPT-6 Astra, Sol, Luna and GPT-6.1 Sol are supported with distinct model IDs, dated rates and API long-context rules. Sol 6.1 cached input costs $0.10 or 2.5 Codex credits per million tokens; its Fast purchased-credit billing is 2x and included-subscription quota weighting is 2.5x. Earlier periods retain their recorded factors.
  • Unknown models, dates outside documented coverage and unsupported tiers remain visibly unrated and are excluded from totals. A reference API price is available only in explicitly selected custom simulation.
  • The pricing dialog includes historical/current/custom modes, sourced rate history, catalog verification status and an export of the applied calculation. Legacy custom browser prices are preserved for custom simulation.

See Dated pricing research and maintenance for the August 2025–September 2026 research ledger, evidence gaps, UTC day-boundary convention and update procedure. Historical Codex credit coverage begins at the documented observation on August 11, 2026; older credit rates are not invented.

Weekly quota history is reconstructed only from observed 10,080-minute rate-limit windows. Reset timestamps within five minutes are grouped. If a free or early reset starts a new quota before the previous nominal reset, the new start becomes the previous period's effective end.

Each historical period displays the plan code observed at that time, hourly activity bars, and cumulative usage through its effective end. Capacity is calibrated from rated credits and the peak observed quota percentage; it is an estimate, not an official plan allowance, and no plan-specific capacity is invented. The current-period forecast projects the observed consumption curve to the effective reset using a 24-hour EMA.

Pricing references: ChatGPT Codex plans and credits, Codex Fast multipliers, API pricing, and API Fast mode.

The displayed dollar amount is theoretical API-equivalent cost, not a bill or the subscription price. Observed cache writes are included with their dated rates. Tool fees and unobserved charges remain excluded. Analyzer v8 preserves optional cache-write counters; deploy the receiving hub before updating reporting agents.

Privacy and security

  • The local server listens on 127.0.0.1 by default.
  • Session files are opened read-only.
  • The dashboard never needs an OpenAI API credential and never reads auth.json.
  • Docker mounts only the two session directories and title index, not the .codex root.
  • Browser API responses use an explicit allowlist and exclude analyzer paths, modification times, parse details, message text, and file contents.
  • There is no analytics, telemetry, external font, or CDN asset.
  • In local-only mode, no Codex usage data leaves the machine.
  • In Mesh mode, only the documented minimized snapshot is sent to the explicitly configured hub.

Do not change HOST to 0.0.0.0 unless you intend to expose the local dashboard and its metadata to other reachable devices. Protect MESH_AGENT_STATE_PATH and administrator tokens as secrets. A reporting machine must never hold the private Site's bypass credential.

Data sources and limitations

The dashboard reads:

$CODEX_HOME/sessions/
$CODEX_HOME/archived_sessions/
$CODEX_HOME/session_index.jsonl

Codex session logs are an internal format and may change. Malformed or partially written JSONL lines are ignored so an active session does not break the dashboard.

A user turn can trigger multiple model calls, especially when tools are used. Input usage may include instructions, repository context, prior messages, and tool results—not only text typed by the user.

Development

Root application:

npm run build
npm test
npm run check

Sites application:

cd sites-hub
npm test
npm run lint

The root runtime uses Node.js built-ins and browser-native HTML, CSS, and JavaScript. The Sites adapter uses React/vinext and D1.

Contributions are welcome. Read CONTRIBUTING.md before submitting changes, especially the privacy requirements for fixtures, logs, and local Codex data.

Independence, branding, and license

Local Usage is an independent free-software project and is not affiliated with, endorsed by, or sponsored by OpenAI. “Codex” and “OpenAI” describe compatibility; their trademarks remain the property of their respective owners. The project does not include OpenAI logo artwork.

The complete project, including its original icon and documentation, is free software licensed under GNU AGPL version 3 or any later version. Modified distributed versions remain under the same license, and a modified version used through a computer network must offer its corresponding source code to its users.

Copyright © 2026 capisoft-lib and contributors.

Project structure

public/                  Editable source for the shared browser interface
dist/dashboard/          Generated UI bundle for local, Docker, and Sites builds
docs/                    Sites deployment and reporting-agent guides
mesh-ingress/             Stateless public gateway for signed machine traffic
scripts/                 Deterministic UI build and synchronization tools
src/analyzer.mjs         Read-only Codex session parser
src/usage-collector.mjs  Reusable local collector and optional Mesh sender
src/public-usage.mjs     Browser API privacy boundary and allowlist
src/mesh-*.mjs           Signing, privacy, agent, protocol, and self-hosted storage
agent.mjs                Headless reporting-agent entrypoint
server.mjs               Local dashboard and self-hosted hub HTTP adapter
sites-hub/               Authenticated OpenAI Sites adapter and D1 aggregation
test/                    Parser, UI, pricing, privacy, and Mesh regression tests
start-dashboard.*        Direct Windows/macOS/Linux launchers

Troubleshooting

The dashboard shows no sessions

Confirm that CODEX_HOME contains sessions or archived_sessions, then restart. For Docker, also confirm that all three scoped sources exist below CODEX_DATA_PATH.

The Centralized selector is unavailable

The local server only advertises Centralized mode after MESH_HUB_URL is configured and the machine has valid persistent enrollment state. Provide a fresh one-time code for initial enrollment, then keep the state file and remove the code.

The public Mesh ingress rejects the agent

Confirm that MESH_HUB_URL is the ingress origin and that /healthz returns HTTP 200. Do not give the Site bypass token to the machine. Follow the Mesh ingress guide to verify server-side configuration.

A model uses the reference price

Open the pricing dialog with the $ button, choose Custom simulation, and enter that model's input, cached-input, and output prices per million tokens. Historical mode always uses the dated official catalog; custom rates do not rewrite it.

Port 4317 is already in use

PORT=8080 npm start

PowerShell:

$env:PORT = "8080"
npm start

Custom project groups

Open Projects → Project groups (also available from Settings) to combine two or more projects under a custom name. Edit a group to rename it or change its members; Ungroup restores the original projects. Groups affect project totals, model breakdowns and conversation labels without modifying source sessions. The editor lists projects across all dates. Each project can belong to one custom group. Preferences are saved in this browser only and are not synchronized between browsers or devices.

Exact-name duplicates with a single matching GitHub repository are automatically combined by default. Expand Automatic grouping options on the grouping page to inspect the matches or disable this browser preference. Ambiguous repositories and explicit manual memberships are never combined automatically.

About

Privacy-conscious Codex dashboard for multi-machine usage, quotas, credits, API-equivalent costs, and GPT-6 Sol/Luna pricing.

Topics

Resources

Contributing

Stars

7 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages