Configuration and environment variables
ASP.NET Core reads appsettings.json, appsettings.Development.json, user-secrets (Development), then environment variables. In an environment variable, replace : with __ (for example Llm__Providers__Anthropic__ApiKey).
- Dev loop: non-secrets in
backend/src/Aide.Api/appsettings*.jsonor environment variables; secrets withdotnet user-secrets set "<Key>" "<value>" --project backend/src/Aide.Api(run from the repo root). - Kubernetes: secrets and any extra key go in
deploy/k8s/overlays/local/secrets.env(KEY=value, no quotes). Non-secrets are indeploy/k8s/base/configmap.yamlanddeploy/k8s/overlays/local/app-config-local.yaml. The API loads both as environment variables. Re-rundeploy-local.shafter a change. - Railway (FR-112): every variable per service and environment, and whether it is a literal, a reference, a secret or operator-set, is in
deploy/railway/variables.md. Literals and references live in.railway/railway.ts. Secrets and optional values are set per environment in Railway (railway variable set <NAME> --stdin ...) and listed invariables.ignoreinrailway.ts, so IaC doesn’t plan to delete them.
Values are never shown here. “Secret” means: never commit it, set it only through user-secrets, secrets.env or Railway variables.
Server settings keep their internal aide names (for example ConnectionStrings__Aide). Only the CLI variables were renamed, see the last table.
Settings
| Key (env var form) | Purpose | Default | Secret |
|---|---|---|---|
ConnectionStrings:Aide (ConnectionStrings__Aide) |
PostgreSQL connection | none (required) | yes |
POSTGRES_PASSWORD |
Password for the Postgres container (first init only) | none | yes |
POSTGRES_DB, POSTGRES_USER |
Compose / StatefulSet database name and user | aide |
no |
DataProtection:ApplicationName |
Data Protection app name (keep stable) | aide |
no |
DataProtection:KeysPath |
Key ring directory | /data/keys in a container, else %LOCALAPPDATA%/aide/keys |
no |
Workspaces:Root |
Git working copies and local repos | /data/workspaces in a container, else %LOCALAPPDATA%/aide/workspaces |
no |
Telemetry:ConsoleExporter |
OpenTelemetry console exporter | false (true in Development) |
no |
Seed:Enabled |
Create the seed admin and demo projects | false (true in Development and the local k8s overlay) |
no |
App:PublicBaseUrl |
Browser-facing base URL (absolute http(s), validated at start-up): notification links, the GitHub App manifest’s callback and setup URLs, PR links back to Tevrin | http://localhost:8080 (http://localhost:3000 in Development) |
no |
Approvals:SigningKey |
HMAC key for one-click approval links, at least 32 chars | none: no links are created | yes |
Auth:Cookie:SecurePolicy |
Auth cookie Always, SameAsRequest or None |
SameAsRequest |
no |
Auth:RateLimits:LoginPerMinute |
Login attempts per IP per minute | 5 |
no |
Auth:RateLimits:RegisterPerMinute |
Registrations per IP per minute | 5 |
no |
Live:AllowedOrigins (Live__AllowedOrigins__0, …) |
Extra browser origins allowed on the SignalR hub | empty | no |
Jobs:Enabled |
Run the background job worker | true |
no |
Jobs:PollInterval |
Idle poll interval | 00:00:02 |
no |
Jobs:Concurrency |
Jobs run at once | 4 |
no |
Jobs:LeaseDuration |
Lease before a stalled job is re-queued | 00:05:00 |
no |
Llm:DefaultProvider |
anthropic, openai, ollama or fake |
anthropic |
no |
Llm:RequestTimeout |
Whole provider call, including a streamed answer (FR-161) | 00:30:00 |
no |
Llm:StreamIdleTimeout |
Fails a streamed call that receives no data for this long (FR-161) | 00:02:00 |
no |
Llm:KeyCheckTimeout |
Per key check when a connection is added or re-tested (FR-78); a timeout is UPSTREAM_ERROR |
00:00:15 |
no |
Llm:MaxOutputTokens |
Output token limit per call for models not in their provider’s catalog (and, for Anthropic, whose limit GET /v1/models/{id} couldn’t report). Listed models use their catalog MaxOutputTokens (FR-160). An answer cut off at the limit is continued and joined; one still cut off records the output_truncated run warning |
16000 |
no |
Llm:MaxOutputTokensCeiling |
Optional cap (at least 1) on every call’s output token limit, whatever the catalog says (FR-160) | unset | no |
Llm:Providers:<Name>:Enabled |
Whether the provider (Anthropic, OpenAI, Ollama, Fake) is offered on this deployment (FR-157). A disabled provider is absent from every list, refused on project create and LLM settings (LLM_PROVIDER_UNAVAILABLE), and fails the runs of projects still set to it. At least one must be enabled, and Llm:DefaultProvider must be one of them. Railway sets Ollama and Fake to false |
true |
no |
Llm:Providers:<Name>:Catalog:<n>:Id, Name, MaxOutputTokens, ContextTokens, Recommended |
The provider’s model catalog (FR-158, §4.24): what the wizard offers and each model’s output limit and context window. Shipped in appsettings.json; extend it per deployment with the next index (e.g. Llm__Providers__Anthropic__Catalog__7__Id). Ids must be unique per provider, MaxOutputTokens at least 1. The OpenAI entries (gpt-6-astra, gpt-6.1-sol: 16,000 output, 400,000 context) are unverified placeholders until checked against OpenAI’s model docs (SPEC §11 Q5) |
see appsettings.json |
no |
Llm:AllowSystemKeys |
Whether the system keys below may be used, and then only for projects with no bound connection (D-V2-5, FR-79). Otherwise runs use the key an Owner bound from Account → Connections | false |
no |
Llm:Providers:Anthropic:ApiKey |
Anthropic system key (used only with Llm:AllowSystemKeys=true) |
none | yes |
Llm:Providers:OpenAI:ApiKey |
OpenAI system key (used only with Llm:AllowSystemKeys=true) |
none | yes |
Llm:Providers:<Name>:BaseUrl |
Endpoint override (Anthropic, OpenAI, Ollama, Fake). Ollama: Llm__Providers__Ollama__BaseUrl |
Ollama: http://localhost:11434 (Development, no container) or http://host.docker.internal:11434 (container) |
no |
Llm:Providers:<Name>:DefaultModel |
Model when an agent has no own entry | see section below | no |
Llm:Providers:<Name>:Models:<Agent> |
Model per agent, e.g. Llm__Providers__Anthropic__Models__StackAnalyst for the v5 Stack Analyst (FR-180) |
see section below | no |
Llm:Pricing:<model>:InputPerMTok, OutputPerMTok |
USD per million tokens, for cost estimates | see appsettings; unpriced = 0 | no |
GitHub:App:AppId |
Tevrin GitHub App id (FR-80). All five GitHub:App:* values together override the App registered from Admin → Integrations → GitHub; set none or all |
none: the registered App, if any | no |
GitHub:App:ClientId |
The App’s client id (sign-in and connections) | none | no |
GitHub:App:ClientSecret |
The App’s client secret | none | yes |
GitHub:App:PrivateKey |
The App’s PEM private key; \n escapes allowed (one line in secrets.env) |
none | yes |
GitHub:App:Slug |
The App’s slug (install link https://github.com/apps/<slug>/installations/new) |
none | no |
GitHub:OAuth:ClientId |
GitHub sign-in OAuth App client id (v1; used only while no GitHub App exists, D-V2-7) | none: sign-in disabled | no (treat as config) |
GitHub:OAuth:ClientSecret |
GitHub sign-in OAuth App secret | none | yes |
GitHub:GitBaseUrl |
Where repos are cloned from and pushed to | https://github.com/ |
no |
GitHub:ApiBaseUrl |
GitHub REST API | https://api.github.com/ |
no |
GitHub:ReleaseMergeMethod |
PR merge at release: merge, squash, rebase |
merge |
no |
GitLab:AllowPrivateNetworks |
Allow GitLab hosts that resolve to private ranges (10/8, 172.16/12, 192.168/16, fc00::/7, *.railway.internal). Loopback, link-local and metadata addresses are always refused (SPEC §8). false on Railway |
true (dev loop and the local k8s overlay) |
no |
GitLab:Instances:<n>:Name, BaseUrl, ClientId, AllowInsecureHttp |
Config-defined GitLab instance (FR-130), e.g. GitLab__Instances__0__BaseUrl. BaseUrl empty = https://gitlab.com. Overrides a DB-registered instance (Admin → Integrations → Git hosts) with the same host. Validated at start-up. AllowInsecureHttp permits a plain-http self-managed instance |
none: the DB-registered instances only (AllowInsecureHttp false) |
no |
GitLab:Instances:<n>:ClientSecret |
That instance’s GitLab OAuth application secret | none | yes |
GitLab:RequestTimeout |
One GitLab API request | 00:00:20 |
no |
Bitbucket:OAuth:ClientId |
Bitbucket Cloud OAuth consumer key (FR-133), e.g. Bitbucket__OAuth__ClientId. Overrides the consumer saved in Admin → Integrations → Bitbucket. Set together with the secret (validated at start-up) |
none: the DB-saved consumer only | no |
Bitbucket:OAuth:ClientSecret |
That consumer’s secret | none | yes |
Bitbucket:RequestTimeout |
One Bitbucket API request | 00:00:20 |
no |
Git:Local:ImportRoot |
Folder under which a Local import (git.localSourcePath) must live. Empty disables Local import. E2E and dev only |
unset (/data/import in the E2E overlay) |
no |
Deployments:Provider |
Vercel (the real platform APIs of every deployment provider; the name is historical) or Fake. Fake makes every deployment check deterministic and lets Local Git projects use deployments |
Vercel (Fake in the E2E overlay) |
no |
Deployments:AllowFake |
Allows Fake (for deployments, databases and trackers) outside Development and Testing. Without it the API refuses to start with Fake |
false (true in the E2E overlay) |
no |
Databases:Provider |
Platform or Fake. Fake makes database provisioning and the migration runner deterministic, with no network and no real database. Set it with Deployments:Provider: each is read on its own |
Platform (Fake in Development and the E2E overlay) |
no |
Notifications:AllowPrivateTargets |
Let Slack, Teams, webhooks reach private addresses (local testing only) | false |
no |
Notifications:RequestTimeout |
One webhook request, at most 60 s | 00:00:10 |
no |
Notifications:SweepEnabled |
Run delivery retries and gate reminders | true |
no |
Notifications:DeliverySweepInterval |
How often due retries run | 00:01:00 |
no |
Notifications:GateSweepInterval |
How often gates are checked for reminders | 01:00:00 |
no |
Notifications:DatabaseExpirySweepInterval |
How often the database_expiry_sweep job is queued: it reads each database’s state to raise “database expiring” and mark expiring/paused (FR-155). Positive |
01:00:00 |
no |
Notifications:ConnectionExpirySweepInterval |
How often Jira and Linear connections are checked for a user-entered expiry within 14 days, raising “connection expiring” (FR-165). No provider calls. Positive | 01:00:00 |
no |
Trackers:Provider |
Issue trackers for imports (Jira, Linear, GitHub, GitLab; FR-165..FR-169): unset or Real = the real APIs with each user’s own connection, Fake = recorded fixtures with no network. Any other value stops the API at start-up. Fake outside Development and Testing also needs Deployments:AllowFake=true. Never set on Railway |
unset (real; Fake in CI E2E and the E2E overlay) |
no |
Trackers:SearchTimeout |
One tracker search or fetch; over it the call fails with UPSTREAM_ERROR. Greater than zero and at most 00:02:00 |
00:00:15 |
no |
Notifications:SweepBatchSize |
Deliveries retried per sweep | 50 |
no |
Smtp:Host |
SMTP server. Blank: email skipped, other channels still send | blank | no |
Smtp:Port |
SMTP port | 587 |
no |
Smtp:Username |
SMTP user | none | no |
Smtp:Password |
SMTP password | none | yes |
Smtp:From |
Sender address | aide@aide.local |
no |
Smtp:EnableSsl |
TLS for SMTP | true |
no |
Smtp:Timeout |
One whole send, positive and at most 00:01:00 |
00:00:15 |
no |
BACKEND_URL |
Web server only (frontend/server.ts): API origin it proxies /api to, WebSocket included |
http://localhost:5080 |
no |
TRUST_EDGE_FORWARDED |
Web server only: keep the edge’s X-Forwarded-Proto/-Host. true on Railway |
unset (off) | no |
PORT |
Web server listen port (and Railway healthcheck port) | 8080 (3000 in dev) |
no |
ForwardedHeaders:ForwardLimit (ForwardedHeaders__ForwardLimit) |
Forwarded hops the API trusts. 2 on Railway (edge, web) |
1 |
no |
ASPNETCORE_ENVIRONMENT |
Development (dev loop) or Production (k8s) |
set by launch profile / configmap | no |
ASPNETCORE_FORWARDEDHEADERS_ENABLED |
Trust the web server’s X-Forwarded-* |
true in the k8s configmap |
no |
GitHub:AllowInsecureGitBaseUrl exists for tests only. Do not set it.
Egress (v5 issue imports): with real trackers the API calls *.atlassian.net (only https://<site>/_edge/tenant_info, to resolve a Jira site), api.atlassian.com (Jira REST) and api.linear.app (Linear GraphQL). GitHub and GitLab issues use the hosts Tevrin already reaches (api.github.com, registered GitLab instances). Allow these if outbound traffic is filtered. Trackers:Provider=Fake makes no tracker calls.
Where each value lives
| Kind | Dev loop | Kubernetes |
|---|---|---|
| Secrets (marked “yes”) | dotnet user-secrets set "<Key>" "<value>" --project backend/src/Aide.Api |
deploy/k8s/overlays/local/secrets.env, as Key__Sub=value |
App:PublicBaseUrl |
appsettings.Development.json (http://localhost:3000) |
app-config-local.yaml |
Deployments:*, Databases:Provider, Trackers:Provider, Git:Local:ImportRoot, Llm:DefaultProvider for E2E |
environment variables | deploy/k8s/overlays/local-e2e/app-config-e2e.yaml (--e2e only) |
| Other non-secrets | appsettings*.json or environment variables |
deploy/k8s/base/configmap.yaml |
Platform tokens (Vercel, Netlify, Cloudflare, Render, Railway, Supabase), database connection strings, user LLM keys, GitHub, GitLab and Bitbucket user tokens, registered GitLab instances and the Bitbucket consumer, the registered GitHub App and deployment env values are not configuration. They are stored encrypted in the database and are never shown.
CLI variables
| Variable | Purpose | Fallback |
|---|---|---|
TEVRIN_TOKEN |
API token for the CLI | AIDE_TOKEN |
TEVRIN_API_URL |
API base URL | AIDE_API_URL |
TEVRIN_CONFIG |
CLI config file path | AIDE_CONFIG |
TEVRIN_GIT_TOKEN |
Git host PAT for project init and stack detect |
AIDE_GIT_TOKEN |
Resolution order: flag, TEVRIN_*, AIDE_*, config file, default. An empty value counts as unset. See the CLI guide.
Railway
Every Railway variable per service and environment is in deploy/railway/variables.md. Literals and references live in .railway/railway.ts. See Railway.