Skip to main content

Configuration

ChatWalaʻau has two configuration surfaces, and which one a setting lives on is decided by a rule rather than case by case:

SurfaceHoldsChanged by
.envBootstrap values (ports, paths, endpoints), every secret, and every feature enable-gate / allowlistEditing the file, then restarting
App Settings (app_settings.jsonc)Runtime tuning knobs -- generation, chat & session, memory, speech, RAG, limits, scheduleThe in-app screen, or the CLI

Run chatwalaau init to generate a .env, edit the values, and restart. Everything else is adjustable from the running app.

Changed in v0.129.0

52 variables moved out of .env into App Settings. A leftover value in your .env is ignored -- the server still starts, but that value no longer applies. The startup log names every key it finds. To carry an existing configuration across:

chatwalaau settings migrate # dry run -- shows what it would copy
chatwalaau settings migrate --write # apply, then restart

Required settings​

ChatWalaʻau needs at least one chat provider -- Azure OpenAI, Anthropic (Claude), OpenAI, Microsoft Foundry, or any combination. Configure whichever you have access to; you only need one to start. Models from every configured provider appear in the same selector and can be switched per turn.

Changed in v0.107.0

Chat models are configured exclusively through the Model Offering Catalog (model_offerings.jsonc). The legacy per-provider model variables (AZURE_OPENAI_MODELS, ANTHROPIC_MODELS, OPENAI_MODELS, FOUNDRY_MODELS, MODEL_MAX_CONTEXT_TOKENS, ANTHROPIC_HOSTING, and the per-provider chat endpoint/key variables) have been removed. Run chatwalaau init (first-model wizard), chatwalaau models add, or the in-app App Settings screen.

Set your provider credentials in .env (shared with image, RAG, and speech):

AZURE_OPENAI_ENDPOINT=https://<your-resource>.openai.azure.com/
AZURE_OPENAI_API_KEY=<your-key> # OR authenticate with Entra ID (see Authentication)
# ANTHROPIC_API_KEY / OPENAI_API_KEY as needed -- referenced by NAME from the catalog

Then author at least one chat offering in model_offerings.jsonc. Each offering self-describes its provider (azure-openai / anthropic / openai / foundry), model_ref (the real model/deployment name), optional endpoint / base_url / hosting / context_window, and an api_key_env (the NAME of the env var holding its key). One endpoint can front several model families, and direct + Foundry-hosted Claude coexist via per-offering hosting:

{
"offerings": [
{ "id": "gpt-5.5", "provider": "azure-openai", "model_ref": "gpt-5.5",
"endpoint": "${AZURE_OPENAI_ENDPOINT}", "default": true, "context_window": 1050000 },
{ "id": "claude", "provider": "anthropic", "hosting": "direct",
"model_ref": "claude-sonnet-4-5-20250929", "api_key_env": "ANTHROPIC_API_KEY" },
{ "id": "gpt-5.1", "provider": "openai", "model_ref": "gpt-5.1", "api_key_env": "OPENAI_API_KEY" },
{ "id": "deepseek", "provider": "foundry", "model_ref": "deepseek-v4-pro",
"endpoint": "https://<resource>.services.ai.azure.com/api/projects/<project>" }
]
}

An azure-openai offering may omit endpoint/api_key_env to reuse the shared AZURE_OPENAI_ENDPOINT + Azure credential lanes. A non-demo deployment with no chat offering still boots (with a startup warning, so the App Settings screen stays reachable); chat is unavailable and returns a message pointing at the fix when you try it.

You do not have to hand-edit that file: set up your first model as an optional step of chatwalaau init (skip it with --no-model) or any time with chatwalaau models add, and manage the catalog going forward from the App Settings screen in the chat sidebar -- saves apply immediately via hot reload, no restart.

See Models & Reasoning for multi-model switching, the Model Offering Catalog, Anthropic foundry hosting, the OpenAI and Microsoft Foundry providers, and the per-agent generation options.

Authentication​

You choose how the runtime proves its identity to each provider. An API key is the simplest path where available and needs no Azure CLI or tenant; Microsoft Entra ID lanes are available for Azure OpenAI, for Anthropic on Foundry, and for Microsoft Foundry (which is Entra-only).

Azure OpenAI​

The backend resolves Azure OpenAI credentials through four lanes, selected by two variables. Pick the one that matches where you run.

LaneWhen to use.env setting
api-keyFirst run / PoC / CI / container; cross-tenantAZURE_OPENAI_API_KEY=<key>
cli (default)Localhost dev with az login (Entra ID)AZURE_CREDENTIAL_MODE=cli (or unset)
managed-identityAzure App Service, Container Apps, AKS, Functions, VM (Entra ID)AZURE_CREDENTIAL_MODE=managed-identity
defaultOne image across many surfaces (Entra ID auto-discovery)AZURE_CREDENTIAL_MODE=default

Precedence: AZURE_OPENAI_API_KEY always wins over AZURE_CREDENTIAL_MODE. So if you set an API key you do not need az login. One INFO log line per process announces the active lane on first credential resolution; the key value is never logged.

AZURE_TENANT_ID names the tenant of your Azure resources. The cli and default lanes request their token for that tenant. Without it, if your default az login tenant is a different one, Azure answers HTTP 400 "Token tenant ... does not match resource tenant". The api-key and managed-identity lanes ignore it.

Why Azure authentication stays in .env

AZURE_CREDENTIAL_MODE, AZURE_TENANT_ID and AZURE_OPENAI_API_KEY are not App Settings, for three reasons:

  • The credential is built once per process and shared by every Azure lane: Azure OpenAI, Microsoft Foundry, Anthropic on Foundry, speech, Live, RAG and image.
  • The pnpm dev:full and Desktop startup scripts read AZURE_TENANT_ID for their az login check before the backend starts.
  • The API key is a secret.

Change them in .env, then restart.

AZURE_OPENAI_ENDPOINT is different: it is only the default endpoint for Azure offerings that name none. You do not need it when every Azure offering names its own endpoint.

Cloud deployments

For managed-identity, assign a Managed Identity to the compute and grant it the Cognitive Services OpenAI User role on the Azure OpenAI resource. User-assigned identities also need AZURE_CLIENT_ID. AKS workloads using federated identity should use AZURE_CREDENTIAL_MODE=default so the SDK's WorkloadIdentityCredential is picked up. The chatwalaau CLI skips its az account show precheck whenever the active lane is not cli.

Anthropic (Claude)​

Claude models are catalog offerings with a per-offering hosting:

HostingWhereAuth
direct (Anthropic public API)optional base_url proxyapi_key_env naming a variable that holds sk-ant-...
foundry (Anthropic on Microsoft Foundry)required base_url: https://<resource>.services.ai.azure.com/anthropicapi_key_env, or omit it for Microsoft Entra ID (AZURE_CREDENTIAL_MODE + AZURE_TENANT_ID)

ANTHROPIC_HOSTING and the ANTHROPIC_FOUNDRY_* variables are retired; see Models & Reasoning -> Anthropic provider.

OpenAI (direct)​

The OpenAI public API authenticates by API key only -- there is no Entra ID lane.

Auth.env
API keyOPENAI_API_KEY=sk-... (optional OPENAI_BASE_URL for OpenAI-compatible gateways)

Details are in Models & Reasoning -> OpenAI provider.

Microsoft Foundry​

Foundry project endpoints authenticate with Entra ID only -- there is no API-key lane. The provider reuses the Azure OpenAI Entra lanes (AZURE_CREDENTIAL_MODE + AZURE_TENANT_ID); AZURE_OPENAI_API_KEY does not apply.

Auth.env
Microsoft Entra IDthe foundry offering's endpoint (https://<resource>.services.ai.azure.com/api/projects/<project>); reuse AZURE_CREDENTIAL_MODE + AZURE_TENANT_ID

Grant the signed-in identity a Foundry data-plane role (for example Azure AI User) on the project. Details are in Models & Reasoning -> Microsoft Foundry provider.

API keys for callers​

Callers of ChatWalaʻau's own API (the CLI from another machine, scripts, an app using /v1/responses) use API keys that you issue per caller. They live in API_KEYS_FILE (default api_keys.jsonc; on Azure App Service a path under /home), hashed. Since v0.215.0 there is no API_KEY in .env.

Make the first key in the API Keys screen (signed in, or on the same machine) or on the server:

chatwalaau keys create --name my-cli --scope api

See Authentication for scopes, expiry and disabling a key.

Application settings​

Everything that tunes runtime behaviour is edited in the app, not in .env. Open App Settings from the sliders icon in the sidebar footer. The screen has a settings-item list on the left -- the Model Offering Catalog, then one item per group:

GroupExamples
Generation & inferenceAnthropic token floor, prompt caching, web-search country
Chat & sessionChat-title mode, PDF attachment handling, import size cap, history compaction, folder cues (glow, name badge)
MemoryIdentity / user / agent-memory toggles and character limits
SpeechThe TTS voice and the realtime sample rates; the Live voice and limits. The STT / TTS models are Model Offering Catalog offerings
RAGVector collection, retrieval breadth
LimitsShell timeout, file-explorer caps, pipeline pool, workflow caps, reply caps
OntologyOntology file and answer caps, query cache, history retention, imports (include by default, limits)
ScheduleCron tick, grace window, run timeout, timezone
Agent SkillsSkill installation switch, catalog and ledger paths, source table, GitHub token, install caps

When a change takes effect​

Each control carries a badge, because a setting that is saved but not yet live must not look like it took effect:

BadgeMeaning
Applies immediatelyThe value is live as soon as you save (50 settings).
Rebuilds agentsSaving rebuilds the per-model agents in place; still no restart (13 settings).
Restart requiredThe value is saved now and applies after you restart the server (2 settings -- the pipeline worker pool and the skills install ledger path).

ChatWalaʻau never restarts itself. For a restart-scope change the screen names the keys that are waiting on you.

Settings that depend on another setting​

Some settings are only read while another setting is switched on. Those rows render disabled, with a Needs <parent> chip naming the switch that controls them -- the three history-compaction budgets, for example, grey out while History compaction is off. The relationship is declared by the backend, so the screen always greys out exactly what the server ignores.

Two things follow, and both matter in practice:

  • Turning the parent off does not discard your values. They stay in app_settings.jsonc, stay validated, and come back exactly as you tuned them when you switch the parent back on. A toggle is not a reset.
  • A setting named in a rejected save stays editable, whatever its parent is doing. If a save is refused because two settings conflict, you can always fix them on the screen that refused it.
Compaction settings

The history-compaction settings are badged Rebuilds agents, and that badge was not true until 0.148.0: the rebuild re-used the compaction strategy built when the process started, so a save reported success while the running agents kept the old value. Saving now applies to the next turn, on every surface.

As of 0.149.0 there is no strategy picker. COMPACTION_STRATEGY is removed and replaced by an on/off switch plus two budgets -- tool-call groups (12) and message groups (25) -- which must satisfy 2 x K < N. Upgrading requires no action; see Conversation compaction.

As of 0.150.0 the two budgets and the system-prompt exemption are disabled in the screen while the on/off switch is off, since the pipeline never reads them. Their values are kept, so switching compaction back on restores the budgets you set.

As of 0.217.0 the budgets default to 24 and 50, and two settings join them: compaction_keep_skill_context (Compaction: keep skill instructions, on) and its child compaction_skill_context_max (Compaction: skills kept, 4, 1..16). A value you saved is kept. See Skill instructions are kept.

As of 0.218.0 the OpenAI-compatible API group adds responses_reject_unknown_model (Refuse unknown models, off) and responses_session_retention_days (Keep API conversations (days), 0 = forever). See Document desk.

As of 0.220.0 the same group adds responses_route_timeout_seconds (Routing timeout (seconds), 5, 1..30) and responses_route_min_probability_percent (Routing minimum probability (%), 60, 1..100) for requests with "route": "auto". See Routing questions.

From the CLI​

chatwalaau settings list # every setting with value, group, and scope
chatwalaau settings list --json # machine-readable
chatwalaau settings migrate # dry run: what would move out of .env
chatwalaau settings migrate --write # apply

Upgrades and rollbacks​

  • A key this build does not recognise is kept, not deleted. A settings file written by a newer release will not stop an older release from starting; the unknown keys appear under Unknown / deprecated settings with a delete control.
  • A value that is no longer valid does not block startup. It falls back to the built-in default with a warning, and the field shows a chip.
  • APP_SETTINGS_FILE (default app_settings.jsonc, relative to the working directory) is the one .env key this surface adds. Set it empty to disable the store entirely and run on built-in defaults.

How the .env is organized​

The template groups settings by feature. Most features are opt-in and default off, so the server works after install with only the required Azure settings. Each feature page in this documentation lists the settings it uses; this page is the entry point, not an exhaustive table.

Note the deliberate split between a feature's gate and its bounds: CODING_ENABLED stays in .env while CODING_BASH_TIMEOUT is an application setting. A gate decides whether a capability exists at all; a bound only narrows one you already enabled. Only the first is a security decision, so it is not editable from a screen. Computer Use follows the same rule: COMPUTER_USE_ENABLED, its data directory, its secrets file and an optional desktop provider command (COMPUTER_USE_PROVIDER_COMMAND) are .env keys, and its tuning is the Computer Use group in App Settings (v0.170.0).

The one exception is the CodeAct compute sandbox: its switch lives in App Settings (CodeAct, off by default, v0.172.0), because what it protects is enforced where a screen cannot reach -- the sandbox has no files, network or OS access in code, and demo mode closes it regardless.

MCP servers are configured from the MCP Servers screen (v0.206.0), but one decision stays a .env gate: MCP_STDIO_REMOTE_EDIT (default false). A stdio MCP server runs a command on the server machine, so the screen adds, edits or tests stdio servers only for a request made on that machine unless you set it to true. See Knowledge & MCP.

Skills, and the one directory to keep​

SKILLS_DIR (default .skills) is where Agent Skills live -- and since v0.151.0 it is also where the product writes everything it knows about them: the skill catalog, the record of what you installed and from where, and your enable/disable selection. They are hidden files inside that directory, so one mount covers the whole feature.

On a container platform, mount persistent storage at SKILLS_DIR if installed skills must survive a restart. Without it they are lost on recycle -- the product reports the loss instead of hiding it, but it cannot prevent it.

SKILLS_DIR is the only skills setting in .env, and it is there by rule: the catalog file and the ledger file resolve under it, so the root has to be readable before the rest can be found. Everything else is in App Settings, under the Agent Skills group -- no file edit, no restart.

SettingWhat it does
Skill installationMaster switch for the write side: catalog refresh, install, reinstall, uninstall. Browsing keeps working when it is off.
Catalog file / Install ledger fileWhere the snapshot and the ledger are written. Relative paths resolve under SKILLS_DIR.
Source table filePath to your own JSON source table, replacing the five built-in sources.
GitHub tokenOptional; raises GitHub's 60 requests/hour limit for anonymous callers.
Source request timeout, Install size cap, Install file-count capBounds on one fetch and one installed skill.

The five rows below the switch grey out while Skill installation is off, because those are the values the backend stops reading. The two file paths do not: browsing the catalog and your enable/disable selection keep working either way.

Installation is always unavailable in demo deployments, whatever the switch says -- DEMO_MODE lives in .env and outranks it. That is what makes it safe for the switch itself to be editable from a screen.

The GitHub token is stored, but never sent back

It is the first credential App Settings holds. The screen shows a masked password field: leaving the mask alone is what keeps the token when you save some other setting, and clearing the field clears the token. Because app_settings.jsonc can now contain a credential, give it the same file permissions you give .env.

Keeping .env current across releases​

New releases usually add value through new opt-in settings, so the server keeps working after pip install -U -- but you cannot tell from your own .env which settings became available, and old keys pile up. Two offline commands reconcile your .env against the template bundled with the installed release:

chatwalaau env diff # settings added / removed since your .env was made
chatwalaau env diff --json # machine-readable

chatwalaau env sync # preview the reconciliation (dry-run)
chatwalaau env sync --write # apply, after writing a timestamped backup
  • Your values are preserved verbatim -- only layout and per-key comments are refreshed to the installed release.
  • Nothing is deleted -- keys the template no longer has move to an Unmanaged keys section.
  • A timestamped backup (.env.<UTC>.bak) is written before --write.

On startup, the server logs one line when your .env is missing newly added keys.

Next steps​