Configuration

Everything is optional - the defaults are sensible. Config is layered, so you only set what you need.

Where config comes from

Lowest to highest precedence (higher wins):

precedence
defaults
  < preset (--preset / AICC_PRESET)
  < ~/.ai-command-center/config.json
  < ./aicc.config.json
  < --config <file>
  < environment variables
  < CLI flags

Full config reference

jsonc
{
  "port": 4321,
  "host": "127.0.0.1",              // 0.0.0.0 to share on a LAN/server
  "auth": true,                     // false = no login / no gateway keys

  // Browser origins allowed to call the gateway cross-origin (web apps calling
  // the proxy from the browser). Same-origin + server-side apps never need this.
  "allowedOrigins": [],

  // OPTIONAL central provider keys - injected only when the caller sends none
  // (and never for untrusted cross-origin requests). Callers' own keys win.
  "keys": { "openai": "sk-...", "anthropic": "sk-ant-..." },

  // Custom OpenAI-compatible providers (Azure OpenAI, vLLM, internal gateways…).
  // Their models are usually missing from the public price sheet - add a
  // "pricing" entry per model or requests record unpriced (cost 0). See docs/providers.
  "providers": {
    "azure": { "upstream": "https://x.openai.azure.com", "kind": "openai", "authHeader": "api-key" }
  },

  // Point a built-in provider elsewhere (region endpoint, test double)
  "upstreams": { "openai": "http://localhost:8080" },

  // Opt-in provider routing: fail over / load-balance across a same-schema pool.
  // Reached at /r/<route>/… . strategy: "failover" (default) or "round-robin".
  "routes": {
    "chat": { "members": ["groq", "together", "openrouter"], "retryOn": [429, 500, 502, 503, 504] }
  },

  // Extend/override pricing (USD per 1M tokens, longest-prefix match;
  // "provider:*" sets a provider-wide default). These always win.
  "pricing": { "my-finetune": { "in": 1.0, "out": 4.0 } },

  // Live prices are pulled from the LiteLLM sheet (US), cached + refreshed daily,
  // with the shipped table as the offline fallback. Set to null to disable.
  "pricingUrl": "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",

  // Optional retention: prune request records older than N days (null = keep all)
  "retentionDays": null,

  // Display currency (data is always stored in USD; converted at display time)
  "currency": { "default": "INR", "options": ["INR", "USD", "EUR"], "rates": null },

  // Dashboard/CLI branding (see presets for a company build)
  "branding": { "name": "AI Command Center", "accent": "#3987e5", "tagline": "..." }
}

Environment variables

VarPurpose
AICC_PORTGateway port
AICC_HOSTBind host
AICC_DATA_DIRTelemetry directory
AICC_PRESETConfig preset name
AICC_GATEWAYGateway origin (used by the SDKs/examples)
AICC_KEYProject gateway key (used by the SDKs when auth is on)

Presets & company builds

A preset seeds branding/currency/etc. that your own config still overrides. This is how the same codebase serves both an open-source default and a company build:

bash
npx ai-command-center start --preset example
# or in a config file:  { "preset": "example", "keys": { ... } }

Add your own under presets/<name>.json - the format is just a partial config.

Currency & exchange rates

Costs are stored in USD and converted for display. Rates are refreshed every 12 hours (ECB via frankfurter.app, with an open.er-api.com fallback and a built-in offline fallback) and cached in your data dir. Pin them yourself to skip fetching entirely:

jsonc
"currency": { "default": "INR", "options": ["INR","USD","EUR"], "rates": { "INR": 84, "EUR": 0.92 } }