The CLI is the contract for both humans and agents. Human-friendly output is
the default; pass --json for machine-readable output.
scriba
scriba --version
scriba doctor
scriba doctor --no-remote --json
scriba status
scriba status --fast
scriba status --fast --account work
scriba status --no-remote
scriba status --redact --json
scriba context --json
scriba context --json --account work
scriba accounts
scriba accounts alias <id-or-alias> <new-alias>
scriba mcp
scriba schema
scriba config path
scriba config show --json
scriba config init
scriba config telegram --enable --chat-id <id> --bot-token-env SCRIBA_TELEGRAM_BOT_TOKEN
scriba cache status
scriba cache reset
scriba cache prune
scriba cache vacuum
scriba policy validate policy.json
scriba policy list
scriba policy list --config policy.json --json
scriba policy explain --provider codex --account <ref> --rule <id> --limit 100
scriba outbox list --status leased --limit 100
scriba update --check
scriba update
scriba telegram alerts
scriba telegram alerts --refresh
scriba telegram reset --send --provider codex --label weekly --message "🎉 Tibo just reset limits! 🎊"Bare scriba is equivalent to scriba status.
status composes local log summaries and remote provider-window probes when
auth is available. It writes a derived JSON snapshot and SQLite scan stats
unless --no-cache is passed.
doctor checks local source directories, auth paths, remote reachability,
cache schema/WAL state, cache size, and latest snapshot age. It reports ok,
degraded, or broken.
--fast avoids local rescans and provider requests. It combines cached local
status where available with the selected account's latest resident Codex
observation. Account-specific reads never borrow anonymous or another account's
quota snapshot.
scriba accounts and scriba accounts list show every discovered Codex
account, including accounts whose credentials are no longer available. Each
entry keeps separate facts for its stable public acct-… ID, optional alias,
email/plan, credential availability, and last successful observation age.
Authentication sources are configuration, not user-facing identities.
scriba accounts alias <id-or-alias> <new-alias> writes only account metadata;
it does not change Codex login state or move observations between accounts.
Aliases are unique lowercase slugs up to 32 characters. current and strings
that resemble generated account IDs are reserved. Use --redact to omit aliases
and email addresses from account output.
scriba context --json is intentionally JSON-only. It reads the status cache
and server store without provider refresh or mutation and emits the allowlisted
scriba.context.v2 contract. --cache-dir and --state-path override its two
read sources. Sources report independent availability, provenance, freshness,
and reason codes, so a missing Claude observation does not suppress valid
Codex context. Use --account <id-or-alias> to select an account; omission uses
durable current source bindings and then the latest historical account. Unknown
explicit selectors fail rather than falling back.
The checked-in schema is
context.schema.json. See
agent-context.md for source precedence, privacy exclusions,
partial-result behavior, Unix API/SSE cursors, and MCP parity.
scriba mcp is a protocol-pure stdio server for local agent clients. It exposes
only scriba_get_context and scriba_list_events; each accepts an optional
public account ID, alias, or current. It cannot refresh providers, change
config, send notifications, redeem grants, or accept raw provider account refs.
Use --config, --cache-dir, and --state-path to select the same read sources
as the context command. Normal stdin EOF and handled SIGTERM exit cleanly.
scriba config telegram edits the same config file used by the macOS menu bar
settings window. Bot tokens can be stored in the config for app use, or supplied
through telegram.botTokenEnv for terminal-only workflows.
scriba telegram alerts reads the cached status snapshot by default so menubar
actions stay fast. Pass --refresh when you explicitly want it to rebuild status
before evaluating alerts.
scriba telegram reset is the small one-shot send path used by ScribaBar when a
reset heuristic fires. It reads the same Telegram config and only sends when
Telegram is enabled.
scriba claude summary
scriba claude daily
scriba claude weekly
scriba claude monthly
scriba claude sessions
scriba claude blocks
scriba claude budget
scriba codex summary
scriba codex daily
scriba codex weekly
scriba codex monthly
scriba codex sessions
scriba codex limits
scriba codex reset-grants
scriba codex reset --dry-run
scriba codex activity
scriba codex budget
scriba codex limits --fast
scriba codex reset-grants --fast --account workReport commands support --since and --until, accepting full timestamps or
YYYY-MM-DD dates. Calendar reports use the system timezone by default. Set
timezone in the config or pass an IANA name with --timezone, for example
--timezone Europe/Istanbul. JSON report payloads record the resolved
timezone.
Codex local reports expose two intentionally different totals:
effectiveTokensis uncached input plus output. It matches the accounting shape used by Codex goals, subject to the goal's own active time window.totalTokensis full model traffic: input (including cached input) plus output.
inputTokens preserves the raw Codex input counter, including cache reads;
uncachedInputTokens and cachedInputTokens split it explicitly. Reasoning
tokens are already included in output and are not counted again. Human output
leads with effective tokens, keeps traffic/cache/output visible, and lists up
to three materially used exact model names instead of hiding every model except
the dominant one.
Local Codex JSONL reports come from session logs, which do not establish a
provider account identity. Supplying --account scopes the remote limits
appended to summary, but it does not retroactively split local token totals.
JSON reports mark attributionScope: "session_logs" and
accountAttribution: "unavailable"; human output says the same plainly.
Known Codex models receive a calculated costUSD. The human label is est.
because this is a standard-tier API-equivalent estimate, not a claim about
what a ChatGPT subscription was charged. The embedded catalog records its
review time and current Standard rates. GPT-5.6 Sol, Terra, and Luna use
short-context input/cache/output prices and per-request long-context rates
above 272K input tokens. The whole request switches tiers; reasoning is not
billed separately. Unknown models retain costUSD: null and
pricingState: "missing".
scriba codex limits skips local log scanning and only fetches Codex usage
windows for the selected account. Omit --account to use the highest-priority
usable auth source, or pass a public ID or alias. OpenAI API key auth cannot
expose these ChatGPT subscription windows. The live payload includes primary Codex
windows, explicit additional model windows such as Spark, and the available
rate-limit reset grant count. When the read-only reset-credit metadata endpoint
answers, Scriba also shows the earliest available grant expiry. Pass --fast
to read the selected account's latest resident observation, including its age
and stale state, without making a provider request.
scriba codex summary keeps the local usage summary and, unless --no-remote
is passed, appends the same live Codex limits and reset-grant metadata.
scriba codex reset-grants shows available rate-limit reset grants as a focused
view, including every available grant's grantedAt and expiresAt timestamp
when OpenAI exposes the read-only reset-credit metadata. The short alias is
scriba codex grants. For an explicitly selected historical account without
credentials, the command falls back to stored grant metadata; --fast requests
that behavior directly.
scriba codex reset requires usable credentials for the selected account,
fetches current usage and grant metadata, selects the
available credit expiring soonest, prints the exact credit, and requires an
explicit y confirmation before redeeming it. Use --credit <id> to pin a
specific available grant, --dry-run to stop before the redeeming POST, or
--yes for deliberate noninteractive use. JSON redemption requires --yes;
JSON previews use --dry-run. Each attempt sends one UUID idempotency key and
the selected credit ID, then reports one of reset, nothing_to_reset,
no_credit, or already_redeemed. Scriba does not retry a timed-out mutation
with a new key: it retries one transient failure with the same key. Telegram
exposes the same operation only through an owner-bound, expiring confirmation
callback; MCP remains read-only. The preview pins the resolved public account,
private provider identity, credit, and idempotency key. Auth rotation before a
retry or confirmation refuses redemption and requires a fresh preview.
scriba codex activity shows the ChatGPT/Codex profile token-activity backend:
lifetime and peak tokens, streaks, longest turn duration, reasoning/fast-mode
mix, thread and skill counts, daily/weekly activity bars, and top skills/plugins.
--json preserves the full daily, weekly, and cumulative daily bucket arrays
for agents. The backend currently reports complete generated buckets, so the
current day may be absent until OpenAI generates the next profile snapshot.
These provider-generated buckets have no model attribution and are independent
from local rollout accounting, timezone grouping, and API-equivalent cost
estimates; do not expect exact day-by-day reconciliation.
scriba codex budget and scriba claude budget fetch current provider quota
windows and derive pacing, safe allowance, projected exhaustion, risk,
freshness, confidence, and explicit reason codes. Budget quantities are quota
percentage points, not local token counts: 3pp/h means three points of the
provider-reported quota percentage per hour. These commands deliberately do
not accept --fast. An explicitly selected historical Codex account without
credentials can still derive a visibly stale budget from its stored
observation; live/current requests use fresh provider data.
Codex can use matching durable server observations from the preceding 24 hours
for its recent-burn estimate; samples less than 10 minutes apart are ignored.
Claude currently reports honest current-cycle confidence because it has no
durable quota-window history. Derived budget values are never persisted. The
machine-readable contract is scriba.budget.v1, validated by
schemas/budget.schema.json. See
budget-and-policy.md for the full checkpoint and its
current runtime boundary.
The Wave 2 inspection commands are read-only:
scriba policy validate <file>strictly parses an operator-supplied policy file without opening server state. Its JSON schema version isscriba.policy-validate.v1.scriba policy listrenders the built-incurrentpreset;--config <file>instead parses and lists that file. Its JSON schema version isscriba.policy-list.v1.scriba policy explainopens server SQLite read-only and lists persisted evaluations, filterable by exact--provider,--account, and--rulevalues. Its JSON schema version isscriba.policy-explain.v1.scriba outbox listopens server SQLite read-only without claiming messages and filters by exact--id,--status, and--targetvalues. Its JSON schema version isscriba.outbox-list.v2.
The state-backed commands accept --state-path, --env, and a --limit from
1 to 1000. --redact on policy explain removes subject/account/config
identifiers and persisted state/evaluation bodies. On outbox list it removes
account/target identifiers, delivery payloads, lease/provider message
identifiers, and last errors. The checked-in Draft 2020-12 schemas are
policy-validate.schema.json,
policy-list.schema.json,
policy-explain.schema.json, and
outbox-list.schema.json.
Invalid policy validate --json input still exits nonzero but writes a typed
valid: false envelope to stdout. State inspection uses SQLite mode=ro: it
does not change the main database, schema, business rows, delivery attempts, or
leases. SQLite may still coordinate a live WAL reader through transient
-shm/-wal bookkeeping; this is not presented as byte-immutable sidecar
behavior.
The resident server stores every available reset credit from the read-only metadata endpoint when present. Telegram grant-expiry warnings are deduped by grant id, expiry timestamp, and checkpoint, and fire once at 5 days, 3 days, and 1 day before that grant's own expiry.
Human metric output aligns labels within each rendered provider/output, so progress bars start in the same column even when labels differ in length.
scriba update --check compares the current binary to the latest GitHub tag and
prints the detected install manager/path. scriba update installs the latest
tag with:
go install github.com/agensfield/scriba/cmd/scriba@<latest-tag>When the binary resolves under a Homebrew Cellar/scriba path, Scriba refuses
self-update and points the user to brew upgrade scriba.
Scriba is a Go binary. Build locally with:
go build -o .build/scriba ./cmd/scribaThe macOS app bundles this native binary directly at
ScribaBar.app/Contents/Helpers/scriba.