Skip to content

Data model

SQLite tables (dgxmm/db.py):

Table Contents
users username, argon2id hash, role (admin / viewer), must_change_pw
cli_tokens SHA-256 of a short-lived admin CLI token, user, scope, expiry (deleted when the command ends)
sessions SHA-256 of the session token, user, CSRF token, client IP, expiry
deployments name, engine, model reference, validated config, state, container id, port, priority, alias (the LiteLLM model name), reservation and estimate, LiteLLM status, last error, exit code, whether the last exit was an OOM kill (oom_killed), system (the decision model), mode (on_demand / always_on; NULL reads as always on) and idle_timeout_s (NULL = ondemand_idle_timeout_s, see on-demand gateway). Ids are never reused (AUTOINCREMENT, migration 30).
app_settings runtime settings changed in the UI (key, value, updated at): the LiteLLM URLs, enabled flag, master key and the URL it is bound to; the decision model's decider.* settings
decisions one row per decision-model question: feature, subject, source (rules / model / none), choice, confidence, probabilities, latency, model and revision, SHA-256 of the input, error code, feedback (30 days / 50 000 rows)
diagnoses per failure event: cause, source, confidence, summary, fix hint, patch, redacted log excerpt (latest 20 per deployment; unique per deployment and event)
artifact_kinds model-derived kinds per artifact and snapshot time, with source and confidence
schema_version applied migrations: 1 baseline, 2 one diagnosis per failure event, 3 one live insight per dedupe key, 20 one traffic-profile row per deployment and hour, 30 the deployments rebuild with AUTOINCREMENT (foreign keys off for that step only, checked before and after), 40 the on-demand columns deployments.mode and idle_timeout_s (existing rows become always_on)
deployment_events state transitions with message, optional log tail and, for stops, the actor that asked (user, schedule:<id>, …)
memory_calibration estimated vs measured bytes per engine, model and config hash; OOM records; the reading label
benchmarks one row per concurrency level: TTFT p50/p95, ITL p50, total and per-request tok/s, and the reading label (reading, quality)
benchmark_runs one row per benchmark run: levels, status, the level that failed and its error
metric_rollups 1-minute aggregates per deployment and for the host (30-day retention)
downloads repo, revision, files, progress, state, error
favourites model references starred in the Planner
audit_log user, action, target, details, timestamp
insights kind, feature, subject, severity, templated title and body, confidence, source, decision id, action descriptor, status, snooze end, dedupe key, created / updated / expires at (one live row per dedupe key; closed rows 30 days)
deployment_schedules deployment, action (sleep / wake / stop / start), days bitmask, HH:MM, time zone, enabled, created by, created / updated at, last run (time, local date, result)
traffic_profiles per deployment and hour of the week: requests per minute p50 / p95, active fraction, observed minutes, weeks observed and idle (unique per deployment and hour)
compat_cache compatibility verdicts, reason keys and flags per repo and commit sha (7 days; never file contents)

Live metrics (about the last hour at the scrape interval) are kept in memory only, and so are the on-demand controller's in-flight counters, idle timers and queue.

Schema changes run at startup: new tables and missing nullable columns and non-unique indexes are added, then each versioned migration in dgxmm/migrations.py runs once, in a transaction, recorded in schema_version (see upgrading an existing install). Retention runs once a minute with the metrics rollups; the limits are listed per table above and in startup and background loops.

Next steps