CLI Reference
Reference for the operations CLI at the repository root (cli.py, "AI Token Usage CLI"). It reads and writes the same usage database as the shared scripts (scripts/shared/), so it is safe for daily queries and useful for scheduled maintenance — but three of its commands modify metering data and are covered in a dedicated section below.
Running
All commands are invoked as modules of cli.py from the repository root:
python3 cli.py <command> [options]
python3 cli.py --help
python3 cli.py <command> --help
Shared behavior:
- Running any command initializes the usage database first (
db.init_database()), so the CLI can also bootstrap a fresh environment. - Data source: the usage database configured in
~/.open-ace/config.json(databasesection). Default is SQLite at~/.open-ace/ace.db; apostgresql://URL switches to PostgreSQL (requirespsycopg2). - App configuration is read from
~/.open-ace/config.json(OPENACE_CONFIG_DIRoverrides the directory); theemailsection feeds thereportcommand. - Token counts are printed in both human-readable form (e.g.
1.2M) and the raw number.
Query Commands
today — usage for today
Shows per-tool usage for the current date: total tokens, input/output/cache split, request count, and models used.
| Option | Description |
|---|---|
--tool TOOL | Filter by tool name (e.g. claude, qwen) |
--host HOST | Filter by host name |
python3 cli.py today
python3 cli.py today --tool claude
python3 cli.py today --host dev-machine
query — usage for a specific date
Same output shape as today, for an arbitrary date.
| Argument / Option | Required | Description |
|---|---|---|
date (positional) | Yes | Date in YYYY-MM-DD format (invalid formats are rejected) |
--tool TOOL | No | Filter by tool name |
--host HOST | No | Filter by host name |
python3 cli.py query 2026-09-01
python3 cli.py query 2026-09-01 --tool qwen
top — top tools over the last N days
Aggregates usage by tool over a window ending today, sorted by total tokens. Each tool also shows its request count.
| Option | Description |
|---|---|
--tool TOOL | Restrict the ranking to one tool |
--days N | Window length in days (default 7) |
--host HOST | Filter by host name |
python3 cli.py top
python3 cli.py top --days 30
summary — all-time summary
Per-tool totals over the full history: days tracked, total tokens, average per day, total requests, average requests per day, and the tracked date range.
| Option | Description |
|---|---|
--host HOST | Filter by host name |
python3 cli.py summary
report — email report
Composes an HTML usage report and sends it over SMTP. The reference date is today, or yesterday when the command runs before 08:00 local time — so an early-morning cron still reports the previous full day.
| Argument | Description |
|---|---|
type (positional, optional) | Report type; only email exists (default) |
python3 cli.py report
Notes:
- Requires an
emailsection in~/.open-ace/config.json(smtp_server,smtp_port,smtp_username,smtp_password,from_email,to_email,use_tls); the command exits with a clear error if it is missing. - The SMTP connection is tested before sending; the subject is
AI Token Usage Report - <date>. - The summary table in the email is all-time; the daily table covers the reference date only.
config — configuration management
| Action | Description |
|---|---|
show | Print the current config JSON (with its path) |
init | Create ~/.open-ace/config.json from config/settings.json.sample, or a built-in default; prompts before overwriting |
edit | Open the config in $EDITOR (default nano); runs init first if no config exists |
python3 cli.py config show
python3 cli.py config init
python3 cli.py config edit
Metering Maintenance Commands
These three commands change billing/metering data. Run them against a backed-up database, prefer narrow date ranges or a single --tenant-id, and never run two of them concurrently — aggregate-quota takes a 300-second aggregation lock and records idempotency history, but reset-tenant-period and repair-consistency write directly.
aggregate-quota — rebuild quota and tenant usage aggregates
Two-step pipeline:
daily_messages→quota_usage: counts user messages (role='user') as requests and sums the tokens of the assistant replies linked to them via theparent_idchain.sender_nameis matched to users by username — imported data whose sender does not match any username produces no rows.quota_usage→tenant_usage/tenants: resets expired billing periods, runs a data-quality check, then aggregates per-tenant usage and updates tenant totals under an aggregation lock. A run for an already-aggregated date range is detected and skipped (idempotency history).
| Option | Description |
|---|---|
--start DATE | Start date in YYYY-MM-DD (default: all data) |
--end DATE | End date in YYYY-MM-DD (default: all data) |
python3 cli.py aggregate-quota
python3 cli.py aggregate-quota --start 2026-09-01 --end 2026-09-30
When to use:
- Backfilling after importing historical messages, or repairing
quota_usagerows lost to a failed job. - Re-running a scheduled aggregation that failed partway (safe: lock + idempotency guard).
Risks:
- It rebuilds aggregates that quota checks and reports bill against: a wrong date range or dirty
daily_messagessilently becomes billed usage. A quality score below 90% is logged as a warning — investigate before trusting the run. - With no
--start/--end, it reprocesses all data; prefer bounded ranges when repairing.
reset-tenant-period — manually reset one tenant's billing period
Resets the given tenant's billing counters and starts a new cycle (billing_cycle_start / billing_cycle_end recomputed from the tenant's billing_day and billing_cycle_type).
| Option | Required | Description |
|---|---|---|
--tenant-id ID | Yes | Numeric tenant ID (integer) |
python3 cli.py reset-tenant-period --tenant-id 3
When to use:
- A tenant changed their billing day or plan and the operator must cut the cycle over immediately.
- A cycle was corrupted (for example an aggregation ran with wrong dates) and period counters need a clean restart.
Risks:
- This is a billing boundary change: usage accumulated in the old period stops counting toward it. Usage rows are not deleted, but quotas and reports evaluated from the new period will not see the old cycle's consumption. Confirm the tenant ID — there is no confirmation prompt, and the reset is not automatically reversible.
repair-consistency — recompute tenant totals from tenant_usage
Rebuilds tenants.total_tokens_used and tenants.total_requests_made as SUM(...) over tenant_usage — for one tenant, or every tenant when --tenant-id is omitted.
| Option | Required | Description |
|---|---|---|
--tenant-id ID | No | Limit the repair to one tenant; omit to repair all |
python3 cli.py repair-consistency --tenant-id 3
python3 cli.py repair-consistency
When to use:
- The
consistency_violationstable records detected mismatches between tenant totals and the aggregated usage rows (violation_type,expected_valuevsactual_value,difference,statusofdetected/repaired/ignored). When rows sit indetected, this command performs the repair those rows describe; update the row'sstatus/repaired_atafterwards to keep the audit trail accurate. - After interrupted aggregation jobs that updated
tenant_usagebut died before updatingtenants.
Risks:
- It overwrites tenant totals unconditionally from
tenant_usage: if the underlying aggregation was wrong, the repair entrenches the wrong numbers. Fixaggregate-quotaoutput first, then repair. - It only reconciles the two aggregate layers; it does not re-derive
tenant_usagefromquota_usage(that isaggregate-quota's job).
Exit Codes
Query commands return 0 even when no data matches (they print a "no usage data" message). The maintenance commands exit non-zero on failure: aggregate-quota on tenant-aggregation errors, reset-tenant-period and repair-consistency on any exception, so they can be used in scripted health checks.