Skip to content

Configuration and authentication

Last updated:

Understand configuration precedence, deployment defaults, and API Key behavior.

This page covers deployment settings consumed by AGW Server and logging settings in the Host template. Configure models, Agents, Projects, and integration accounts through the management UI as described in their guides. Choose your deployment mode first, then apply changes and restart the relevant Hosts.

Start with the settings relevant to your task

For an initial local setup, keep defaults and complete initialization. Before relying on the service, locate its database and data directory and follow the backup guide.

For remote access, check listening addresses, allowed origins, proxy trust, and authentication first. For split deployment, begin with the required shared configuration. Polling and batch settings are tuning references; they do not all need changes during initial setup.

Configuration and precedence

General precedence, from low to high: built-in defaults → appsettings.json → environment-specific JSON → Development Secrets → environment variables → command line. Files reside in the Server executable directory, and overrides apply per key. Serilog has a separate configuration reader described below.

Colons denote hierarchy: Database:Provider becomes nested JSON, Database__Provider in the environment, or --Database:Provider postgres on the command line. Use true and false for booleans and the listed names for enums.

“Template” means the repository Host’s appsettings.json. “Omitted” means the key is absent from all configuration sources. Differences are marked explicitly.

Choose settings for your deployment

Deployment topology determines which Server programs you start. Execution mode determines how tasks run. Choose both explicitly.

GroupWhen to use it
Common settingsEvery deployment: endpoints, directories, database, authentication, and logs
Standalone deploymentOne Server manages, schedules, and executes; defaults to SQLite and InProcess
Split Control/Data Plane deploymentSeparate management and execution; requires PostgreSQL and Distributed
Distributed execution tuningAny deployment using Distributed, including Standalone when explicitly enabled

Standalone deployment

For local use or a single Server, start with this default combination. These keys can usually be left unset:

Full keyDefaultMeaning
Database:ProvidersqliteUse a local database file
Database:ConnectionStringData Source=agw.dbSQLite file location; relative paths start from <AgwDataDir>/database/, so the default file is <AgwDataDir>/database/agw.db
Execution:ProviderInProcessRun tasks directly in the current Server
DistributedLock:ProviderUnsetAutomatically use an in-process lock with SQLite
DistributedLock:ConnectionStringEmptyIn-process locks need no database connection

Standalone can also use PostgreSQL while retaining InProcess execution. If you choose Distributed, satisfy the PostgreSQL database and lock requirements below and configure distributed execution accordingly. See Standalone and Docker.

Split Control/Data Plane deployment

Both planes must use the same application database and the combination below. Initialize Control Plane before starting Data Plane.

Full keyRequired settingWhere to configure
Database:ProviderpostgresBoth planes
Database:ConnectionStringThe same PostgreSQL databaseBoth planes
Execution:ProviderDistributedBoth planes
DistributedLock:Providerpostgres, or omit to follow the databaseBoth planes
DistributedLock:ConnectionStringEmpty to reuse the database connection, or the same lock serviceConsistent across both planes

Apply common settings according to each Server’s responsibilities:

  • Control Plane: configure initial setup, management URLs, and public integration OAuth URLs.
  • Data Plane: prepare Agent CLIs, Shell, workspaces, and files. Worker concurrency and polling settings affect execution here.
  • Both planes: check listening URLs, client origins, proxies, logs, and monitoring. Nodes decrypting shared data need matching encryption keys. All execution nodes must be able to access the captured task directories.

Execution mode

All fields below use the prefix Execution:.

SettingDefaultPurpose and accepted values
ProviderInProcessInProcess: execute in the current process. Distributed: coordinate durable execution through PostgreSQL, with workers claiming work. Distributed requires PostgreSQL for both the database and locks.
TurnBroadcastRetentionSeconds300Seconds this Server keeps a finished turn’s replay buffer in memory. Clients that reconnect, or retry the same accepted turn, within this window receive the full replay.

In InProcess mode, turns exist only inside the current Server process. When the Server restarts, running turns left by the previous process end as Interrupted and do not resume; use Distributed for recovery across restarts.

The executable determines the Host role: Standalone combines both planes, Control Plane manages and schedules, and Data Plane executes. Both split Hosts require PostgreSQL, Distributed execution, and PostgreSQL locks. This setting does not change one Host executable into another role.

Distributed locks

All fields below use the prefix DistributedLock:.

SettingDefaultPurpose and accepted values
ProviderUnspecified; follows the databaseinmemory: coordinate within one process, for single-node use. postgres: coordinate multiple nodes through PostgreSQL. When omitted or null, SQLite selects inmemory and PostgreSQL selects postgres.
ConnectionStringEmptyConnection string for PostgreSQL locks. An empty value reuses Database:ConnectionString. In-memory locks do not use a connection string.

Distributed execution tuning

These settings apply to Distributed execution, including split deployments and Standalone with Distributed enabled. Start with the defaults and adjust individual values only to address an observed performance issue.

Distributed workers

All fields below use the prefix Execution:Distributed:.

SettingDefaultPurpose and accepted values
WorkerPollingMilliseconds250Polling interval for pending work in milliseconds. Lower values reduce claiming latency but increase database queries.
MaxConcurrentExecutions4Maximum concurrent executions per execution Server, not a cluster-wide total.
LeaseSeconds30Execution lease duration in seconds. The Server that claims a run holds the lease; if it expires without renewal, another Server may take over the run. Long runs keep renewing, so they are not taken over merely for exceeding 30 seconds.
LeaseRenewSeconds10How often the lease holder renews, in seconds; must be shorter than LeaseSeconds.

All of these fields must be positive integers, and LeaseSeconds must exceed LeaseRenewSeconds, or the Server fails at startup. They are used for worker coordination in Distributed mode.

Execution events and replay

All fields below use the prefix Execution:Distributed:EventStream:.

SettingDefaultPurpose and accepted values
ProviderPostgresEvents always commit to PostgreSQL first. Postgres: read them from PostgreSQL only, without Redis. Redis: also project committed events to a Redis Stream; reads prefer Redis and fill any missing part from PostgreSQL, including expired entries or times when Redis is unavailable. Task records and locks always need PostgreSQL.
ReadPollingMilliseconds250Delay between reads when no new events exist, in milliseconds; must be positive.
ReadBatchSize100Maximum events per read; must be positive.
WriteIntervalMilliseconds250Batch-write delay measured from the first pending event, in milliseconds. 0 writes immediately; negative values are invalid.
WriteBatchSize100Event-count threshold for a write batch; must be positive.
Redis:ConnectionStringEmptyRequired when Redis is selected. Related Servers must use the same Redis service, for example redis:6379,password=....
Redis:StreamTtlMinutes1440Redis Stream retention in minutes, defaulting to 24 hours; must be positive when Redis is selected. Expired entries are read from PostgreSQL instead.

Common settings

These settings apply to either topology. In split deployments, configure them according to each Server’s role.

Server endpoints and directories

SettingDefaultPurpose and accepted values
ASPNETCORE_URLS / --urlsLocal default port 30816; container runtime supplies its bindingListening URLs. Use --urls http://127.0.0.1:30816 for local access or bind another address as required. Separate multiple URLs with semicolons.
ASPNETCORE_ENVIRONMENTProductionSelects environment-specific JSON, such as appsettings.Production.json. Common names are Development, Staging, and Production; custom names are allowed.
AgwDataDir~/agwAGW data root for runtime data, Skills, encryption keys, and related files. Supports ~; other relative paths resolve from the process working directory.
AgwLogDir./logsSeparate log directory; moving the data root does not move it. Supports ~, with other relative paths relative to the working directory.
AllowedHosts*HTTP Host filtering. * allows any hostname; use semicolon-separated hostnames such as agw.example.com;localhost to restrict it. This is not the client-origin list.

Database

All fields below use the prefix Database:.

SettingDefaultPurpose and accepted values
Providersqlitesqlite: a local SQLite file for standalone use. postgres: a PostgreSQL service supporting split and distributed deployment. These are the two supported values.
ConnectionStringData Source=agw.dbConnection string for the selected database. SQLite uses Data Source=..., with relative paths starting from <AgwDataDir>/database/; PostgreSQL uses Host=...;Port=5432;Database=...;Username=...;Password=... with a nonempty Host. Change it together with Provider.

Setup, origins, and reverse proxies

SettingDefaultPurpose and accepted values
Setup:AdminPasswordUnsetInitial administrator password, 8–256 characters. Inject through the environment or Secrets for unattended setup; it does not overwrite existing authentication. Initialize on Control Plane in a split deployment.
Auth:AllowedOriginsagw://app, http://localhost:3000, http://127.0.0.1:3000Allowed client Origin array for CORS and origin checks. Match the actual client scheme and port. The array is empty if omitted.
ReverseProxy:TrustedProxiesTemplate contains 127.0.0.1, 172.16.0.0/12, 10.0.0.0/8Trusted proxies. The current implementation adds only individual IP addresses; CIDR entries are not applied. Configure actual proxy IPs. It processes forwarded For, Host, and Proto headers with a forward limit of 1.

Configure arrays with numeric indices, such as Auth__AllowedOrigins__0=agw://app. Overrides merge by index; overriding index 0 does not remove template entries 1 and 2. Check the complete resulting list.

Integration OAuth URLs

All fields below use the prefix Integrations:OAuth:.

SettingDefaultPurpose and accepted values
PublicBaseUrlhttp://localhost:30816Public Server base URL used to construct the OAuth callback at api/integrations/oauth/callback. For remote deployments, use the public URL reachable by the browser.
WebBaseUrlhttp://localhost:3001Web base URL used after OAuth completes. Set the actual Web URL when using bundled Web or a reverse proxy.

Both accept absolute HTTP(S) base URLs without user information, query strings, or fragments. Omitted or blank values fall back to the current request base URL.

Conversation history writes

All fields below use the prefix ConversationHistory:.

SettingDefaultPurpose and accepted values
ModeIntervalImmediate: write pending data immediately. Interval: buffer and flush periodically. TurnEnd: primarily flush when a turn ends. Reaching the buffer limit also triggers a flush.
FlushIntervalSecondsTemplate: 10; omitted: 5Flush interval in seconds for Interval mode; must be positive and within the supported timer range.
MaxBufferedBytes16777216 (16 MiB)Buffer limit in bytes; must be positive. Reaching it triggers an early flush.

These settings control persistence timing, not whether live output is visible. Buffering reduces writes, but abnormal termination can lose unflushed data. Choose Immediate when prompt persistence matters.

Shell tool

All fields below use the prefix Agents:Shell:.

SettingDefaultPurpose and accepted values
Backendlocallocal: run commands in the project workspace on the execution host. docker: use the Docker Shell executor, mounting the primary workspace at /workspace and additional directories at /project-directories/{id}. It requires Docker; networking is currently disabled and timeout is 30 seconds.

This selects only the AGW Shell tool backend. It does not change Server deployment mode or install external Agent CLIs.

OpenTelemetry

All fields below use the prefix OpenTelemetry:.

SettingDefaultPurpose and accepted values
ServiceNameTemplate: AgwTelemetry service name. Split Hosts replace the template value Agw with Agw.ControlPlane or Agw.DataPlane; when omitted, the fallback is Agw.{HostProfile}.
ServiceVersion1.0.0Service-version label in telemetry.
OtlpEndpointTemplate: emptyOTLP receiver URL. Empty or omitted values disable OpenTelemetry tracing, metrics, and log export.

Logging configuration

SettingDefaultPurpose and accepted values
Logging:LogLevel:DefaultInformationDefault Microsoft logging level; override a category with Logging:LogLevel:{category}.
Logging:LogLevel:Microsoft.AspNetCoreWarningASP.NET Core category level.
Logging:LogLevel:Microsoft.EntityFrameworkCoreWarningEF Core category level.
Serilog:UsingConsole, File, Async sinksAssemblies providing Serilog configuration extensions.
Serilog:MinimumLevel:DefaultInformation; Development: DebugDefault minimum level for the current Serilog pipeline.
Serilog:MinimumLevel:Override:Microsoft.AspNetCoreWarningOverride the ASP.NET Core category.
Serilog:MinimumLevel:Override:Microsoft.EntityFrameworkCoreWarningOverride the EF Core category.
Serilog:MinimumLevel:Override:SystemWarningOverride System; additional categories use the same structure.
Serilog:WriteTo:0:NameAsyncName of the template’s asynchronous sink wrapper.
Serilog:WriteTo:0:Args:configure:0:NameConsoleConsole sink inside the asynchronous wrapper.
Serilog:WriteTo:0:Args:configure:0:Args:outputTemplateSee belowConsole format containing timestamp, level, source, TraceId, SpanId, thread, message, and exception.
Serilog:EnrichFromLogContext, WithMachineName, WithThreadId, WithOpenTelemetryTraceId, WithOpenTelemetrySpanIdAdd context, machine, thread, and tracing identifiers.

The Host reads Serilog separately from appsettings.json and appsettings.{ASPNETCORE_ENVIRONMENT}.json. Do not assume Serilog__... environment variables override this pipeline. Edit the relevant JSON and restart to change its output or levels. Logging and Serilog are separate level configurations; the main output currently uses Serilog.

All Microsoft logging levels are Trace (finest tracing), Debug (diagnostics), Information (normal activity), Warning (potential trouble), Error (failed operations), Critical (severe failures), and None (disabled). Serilog supports Verbose, Debug, Information, Warning, Error, and Fatal. Verbose is its finest tracing level and Fatal denotes severe failures; its minimum levels do not include None.

WriteTo Name, Using, and Enrich values are plugin names, not fixed enums. The table lists the current template. The Host additionally writes AgwLogDir/application-{profile}-.log, rolling hourly, retaining 30 files, and flushing every second. These values are fixed in code rather than configurable keys.

[{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz}] [{Level:u3}] [{SourceContext}] [TraceId:{TraceId}] [SpanId:{SpanId}] [ThreadId:{ThreadId}] {Message:lj}{NewLine}{Exception}

Authentication and API Keys

Remote Web signs in with the administrator password and receives a Cookie. Desktop, Mobile, and automation use API Keys, sent as Bearer credentials:

Authorization: Bearer agw_<your-token>

A request made directly on the Server host is authenticated automatically as administrator 1001, without a password or API Key, when all of these hold: it comes from a loopback address, carries no forwarding headers, targets localhost or a loopback IP as the host name, and carries no authentication header or sign-in Cookie. Requests through a reverse proxy or from another host do not qualify.

API Key plaintext is returned only on creation. Store and supply it through the environment or Secrets, and revoke unused keys. Authentication uses the key creator’s stable ID. Each Server caches a successfully validated API Key for 30 seconds. Revoking a key clears the cache of the Server that handles the revocation at once; in a split deployment without a shared distributed cache, other replicas stop accepting the key within 30 seconds. Multiple login accounts come from the third-party sign-in configuration below; there are currently no configuration keys for roles, API Key scopes, or JWT.

Administrator password hashes, initialization state, and session versions are stored in the database’s global auth group in setting; API Key hashes are in api_token. Management features maintain these values; they are not appsettings entries. Password changes update the session version. Hosts refresh every second and discard cached credentials if refresh fails. To recover a forgotten password, stop Server and run agw-server auth reset-password; split deployments use agw-control-plane auth reset-password. The new password needs 12–256 characters, and resetting it invalidates all existing Web sessions.

Third-party sign-in

Third-party sign-in lets people reach Web and Desktop with an organization account. The first sign-in with an account creates an isolated local user numbered from 10000; the administrator remains 1001. With no provider configured, the administrator password and API Keys continue to work. See Third-party account sign-in for the resulting behavior.

Register AGW at the provider as a web application (confidential client). The callback URL is built from the provider ID. Desktop users go through the same URL: the provider returns the browser to Server, not to the desktop application:

https://agw.example.com/api/auth/oidc/callback/company

The following keys are all prefixed with Auth:Oidc:, where {id} is the ID you choose for a provider.

SettingDefaultPurpose and values
PublicBaseUrlEmptyThe browser-visible Server origin the provider returns to. api/auth/oidc/callback/{id} is appended to it. Use a full origin without a path: HTTPS in production, loopback HTTP allowed in development. Required once any provider is enabled.
WebBaseUrlEmptyWhere the browser lands after sign-in. Leave empty when Web shares the Server origin; set it during source development, where Web runs on 3001 and the backend on 30816.
Providers:{id}:EnabledfalseWhether this provider is available.
Providers:{id}:TypeOidcOidc discovers endpoints from Authority and requests openid profile email. OAuth2 uses explicit endpoints and claim names.
Providers:{id}:DisplayNameProvider IDThe name shown on the sign-in button.
Providers:{id}:ClientIdEmptyClient ID issued when registering AGW at the provider. Required.
Providers:{id}:ClientSecretEmptyMatching client secret. Required; inject it through the environment or Secrets.
Providers:{id}:AuthorityEmptyRequired for Oidc, such as https://sso.example.com/realms/company.
Providers:{id}:AuthorizationEndpointEmptyRequired for OAuth2: where the user authorizes AGW.
Providers:{id}:TokenEndpointEmptyRequired for OAuth2: where Server exchanges the authorization code.
Providers:{id}:IssuerEmptyRequired for OAuth2: identifies the account source and, with the account ID, determines the user.
Providers:{id}:IdentitySourceUserInfoOAuth2 only. UserInfo reads the account from the user information endpoint. AccessToken reads it from a signed JWT access token.
Providers:{id}:UserInfoEndpointEmptyRequired when IdentitySource is UserInfo.
Providers:{id}:AccessTokenIssuerEmptyRequired when IdentitySource is AccessToken: validates who issued the token.
Providers:{id}:AccessTokenAudienceEmptyRequired when IdentitySource is AccessToken: validates the intended recipient.
Providers:{id}:AccessTokenJwksUriEmptyRequired when IdentitySource is AccessToken: where signing keys are published.
Providers:{id}:ClientAuthMethodPostHow OAuth2 client credentials are sent: Post in the request body, Basic in the header.
Providers:{id}:UsePkcefalseEnables S256 for OAuth2. Oidc always uses it.
Providers:{id}:ScopesEmptyOAuth2 scopes, configured by index, such as Scopes__0=read:user.
Providers:{id}:SubjectClaimsubOAuth2 only: field holding the account ID; GitHub uses id. Oidc always uses sub.
Providers:{id}:DisplayNameClaimnameOAuth2 only: field holding the display name; GitHub uses login. Oidc always uses name.
Providers:{id}:EmailClaimemailOAuth2 only: field holding the email address; Oidc always uses email. A missing display name or email does not block sign-in.

Provider IDs use lowercase letters, digits, and hyphens, up to 64 characters, such as company or entra-id. Each ID owns its callback URL; keep it stable after registration.

Example configuration without secrets:

{
  "Auth": {
    "Oidc": {
      "PublicBaseUrl": "https://agw.example.com",
      "Providers": {
        "company": {
          "Enabled": true,
          "Type": "Oidc",
          "DisplayName": "Company account",
          "Authority": "https://sso.example.com/realms/company",
          "ClientId": "agw"
        }
      }
    }
  }
}

Inject the matching secret as Auth__Oidc__Providers__company__ClientSecret. Keep it out of appsettings, frontend environment files, and screenshots. Services that offer OAuth2 only, such as GitHub, use explicit endpoints:

{
  "Auth": {
    "Oidc": {
      "Providers": {
        "github": {
          "Enabled": true,
          "Type": "OAuth2",
          "DisplayName": "GitHub",
          "AuthorizationEndpoint": "https://github.com/login/oauth/authorize",
          "TokenEndpoint": "https://github.com/login/oauth/access_token",
          "UserInfoEndpoint": "https://api.github.com/user",
          "Issuer": "https://github.com/login/oauth",
          "IdentitySource": "UserInfo",
          "UsePkce": true,
          "ClientAuthMethod": "Post",
          "Scopes": ["read:user"],
          "SubjectClaim": "id",
          "DisplayNameClaim": "login",
          "EmailClaim": "email",
          "ClientId": "github-client-id"
        }
      }
    }
  }
}

Authority values for common platforms:

PlatformAuthority
Googlehttps://accounts.google.com
Microsoft Entra IDhttps://login.microsoftonline.com/<tenant-id>/v2.0
Keycloakhttps://sso.example.com/realms/<realm>
Authentikhttps://sso.example.com/application/o/<application-slug>/

Restart the relevant Server after changing these values. In a split deployment, route sign-in requests to Control Plane; Data Plane runs executions with the resulting local credentials. All replicas share one database and Data Protection keys, so a Desktop one-time code can be exchanged on a different replica. Disabling a provider blocks new sign-ins and pending Desktop exchanges; Cookies and API Keys already issued are revoked separately.

Example and verification

This example illustrates configuration syntax. Supply real connection values through the environment or Secrets:

export Database__Provider=postgres
export Database__ConnectionString='Host=db;Port=5432;Database=agw;Username=agw;Password=REPLACE_ME'
export Execution__Provider=Distributed
export DistributedLock__Provider=postgres
agw-server --urls http://127.0.0.1:30816

For split deployment, supply matching database and execution settings to each Host, initialize Control Plane first, then start Data Plane. The example’s agw-server is Standalone; split deployment uses the corresponding Host executables.

After restarting, inspect startup logs, the listening URL, database connectivity, and client sign-in. Validate execution tuning with a small task while observing latency and load. For startup errors, check enum names, numeric ranges, connection strings, and Distributed dependencies. Do not expose passwords or API Keys when sharing logs.

Implementation and references