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
| Var | Purpose |
|---|---|
AICC_PORT | Gateway port |
AICC_HOST | Bind host |
AICC_DATA_DIR | Telemetry directory |
AICC_PRESET | Config preset name |
AICC_GATEWAY | Gateway origin (used by the SDKs/examples) |
AICC_KEY | Project 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 } }