Skip to main content

Config Files

Routerly stores all configuration as JSON files under ~/.routerly/ (or $ROUTERLY_HOME if set). Files are written atomically and are human-readable.

Directory Layout

~/.routerly/
├── app/ # Service binary (managed by installer)
├── config/
│ ├── settings.json # Global settings
│ ├── models.json # Registered LLM models
│ ├── projects.json # Projects, routing, budgets, tokens
│ ├── users.json # User accounts
│ ├── roles.json # Custom roles and permissions
│ └── secret # AES-256 encryption key (plain text, keep safe)
└── data/
└── usage.json # Usage records

settings.json

Global service configuration.

{
"port": 3000,
"host": "0.0.0.0",
"dashboardEnabled": true,
"defaultTimeoutMs": 30000,
"logLevel": "info",
"publicUrl": "http://localhost:3000",
"notifications": []
}
FieldTypeDefaultDescription
portnumber3000TCP port the service listens on
hoststring"0.0.0.0"Bind address. Use 127.0.0.1 behind a reverse proxy
dashboardEnabledbooleantrueEnable or disable the web dashboard
defaultTimeoutMsnumber30000Default provider request timeout in milliseconds
logLevelstring"info"Log verbosity: "error", "warn", "info", "debug"
publicUrlstring"http://localhost:3000"Externally reachable URL, used for notification links
notificationsarray[]Notification channel configurations — see Notifications

models.json

Array of registered LLM model configurations.

[
{
"id": "gpt-5-mini",
"provider": "openai",
"apiKey": "ENCRYPTED:...",
"inputPrice": 0.00015,
"outputPrice": 0.0006,
"cachePrice": 0.000075,
"contextWindow": 128000,
"capabilities": ["chat", "vision"],
"enabled": true
}
]
FieldTypeDescription
idstringUnique model identifier within Routerly
providerstringProvider name: openai, anthropic, gemini, mistral, cohere, xai, ollama, custom
apiKeystringAPI key — stored AES-256 encrypted with the value from secret
inputPricenumberCost per 1,000 input tokens in USD
outputPricenumberCost per 1,000 output tokens in USD
cachePricenumberCost per 1,000 cached/read tokens in USD (optional)
contextWindownumberMaximum context window in tokens
capabilitiesstring[]Supported capabilities: "chat", "vision", "tools", "json_mode"
pricingTiersarrayVolume-based pricing tiers (optional)
enabledbooleanWhether the model is available for routing
baseUrlstringCustom base URL — required for custom provider, used for non-default Ollama hosts
caution

Never edit apiKey values manually. Use the dashboard or CLI to manage API keys; they are encrypted using the secret file.


projects.json

Array of project configurations including routing policies, budgets, tokens, and members.

[
{
"id": "proj_abc123",
"name": "My App",
"slug": "my-app",
"defaultTimeoutMs": 30000,
"policies": ["random"],
"models": ["gpt-5-mini", "claude-haiku-4-5"],
"tokens": [
{
"id": "tok_xyz",
"token": "HASHED:...",
"description": "Production token",
"createdAt": "2024-01-15T10:00:00Z"
}
],
"members": [
{ "userId": "usr_abc", "role": "admin" }
],
"budgets": [
{
"metric": "cost",
"limit": 10.00,
"windowType": "period",
"windowSize": "monthly",
"onExhausted": "block"
}
]
}
]

Project Fields

FieldTypeDescription
idstringInternal project ID (proj_…)
namestringHuman-readable project name
slugstringURL-safe identifier, used in scoped proxy path /projects/{slug}/v1/*
defaultTimeoutMsnumberPer-project request timeout override
policiesstring[]Routing policies in priority order
modelsstring[]Model IDs assigned to the project

Token Fields

FieldTypeDescription
idstringToken ID (tok_…)
tokenstringToken value, stored as a bcrypt hash — the plain sk-lr-… value is only shown once on creation
descriptionstringOptional label
createdAtstringISO 8601 creation timestamp

Budget Fields

FieldTypeDescription
metricstring"cost", "calls", "input_tokens", "output_tokens", "total_tokens"
limitnumberMaximum allowed value for the metric
windowTypestring"period" (fixed calendar window) or "rolling" (sliding window)
windowSizestringFor period: "hourly", "daily", "weekly", "monthly", "yearly". For rolling: "second", "minute", "hour", "day", "week", "month"
onExhaustedstring"block" — return HTTP 503 when budget is reached

users.json

Array of user accounts.

[
{
"id": "usr_abc123",
"email": "admin@example.com",
"passwordHash": "$2b$10$...",
"role": "admin",
"createdAt": "2024-01-01T00:00:00Z"
}
]
FieldTypeDescription
idstringUser ID (usr_…)
emailstringLogin email
passwordHashstringbcrypt hash of the password
rolestringGlobal role name: "admin", "member", "viewer", or a custom role
createdAtstringISO 8601 creation timestamp

roles.json

Array of custom role definitions. The three built-in roles (admin, member, viewer) are not stored here and cannot be modified.

[
{
"name": "billing-viewer",
"permissions": ["usage:read"]
}
]
FieldTypeDescription
namestringUnique role name
permissionsstring[]List of permission strings

Available permissions: models:write, projects:write, users:write, roles:write, settings:write, usage:read, proxy:use.


data/usage.json

Array of usage records, one per LLM request. Written by the service after each completed call.

[
{
"id": "use_abc123",
"timestamp": "2024-01-15T10:30:00Z",
"projectId": "proj_abc",
"projectSlug": "my-app",
"modelId": "gpt-5-mini",
"provider": "openai",
"inputTokens": 150,
"outputTokens": 42,
"cacheTokens": 0,
"totalTokens": 192,
"cost": 0.000048,
"durationMs": 1234,
"status": "success",
"traceId": "trc_xyz"
}
]

This file grows continuously. Routerly does not currently rotate or archive it automatically — back it up and truncate as needed.


secret

A single-line file containing the 32-byte AES-256 encryption key used to encrypt API keys in models.json.

a1b2c3d4e5f6...

Never share or commit this file. If lost, all stored API keys must be re-entered.