Reference
Configuration
This page lists values that the current option types define. It does not infer a
default from provider behavior. null, empty, and off mean exactly that.
Binding rules
Section titled “Binding rules”builder.AddTracon() on an IHostApplicationBuilder reads the Tracon
section. Package extensions then register their capability and read or accept their
own options. A section in a file does not load a package by itself.
var tracon = builder.AddTracon() .UseOpenAI(builder.Configuration.GetSection(OpenAIProviderOptions.SectionName)) .UsePostgreSql(builder.Configuration.GetSection(TraconPostgreSqlOptions.SectionName)) .UseWorkflows() .UseUI();The configuration key separator is :. Environment variables use __, so
Tracon:Providers:OpenAI:ApiKey becomes
Tracon__Providers__OpenAI__ApiKey.
A value that cannot be read stops the host
Section titled “A value that cannot be read stops the host”A number, flag, time span, enum or address key that holds text it cannot read stops the application at startup. The message names the full key and quotes the text, and it lists every such key of the same options type at once:
Tracon:Tools:DefaultMaxOutputBytes is '10MB', which is not a 32-bit whole number.Write a valid value, or remove the key to keep the default.Tracon does not skip such a key and keep the default. Several defaults are the loose
side: 10MB instead of a number would leave tool output unbounded, nope or yes
instead of false or true would leave a protection or a limit as it was. A number is
a whole number or a decimal written with ., a flag is true or false, a duration
is a time span such as 00:00:30, and an enum is one of its member names. A plain enum
takes one member: Tenant,Global is refused, and so is a number that names no member.
Voice:Endpoint, Providers:OpenAI:Live:Endpoint and Mcp:OAuthCallbackBaseUri take an
absolute address such as https://gateway.example.com/v1/; gateway.example.com/v1 is
refused. The Endpoint keys of the model providers are checked by the provider’s own
validator, which refuses a relative address.
- Empty means not given. A key with no text, or only white space, keeps the default.
- A list is written as one entry per key.
EnvironmentAllowList:0=PATHis a list of one;EnvironmentAllowList=PATHis refused, and the message shows the:0form. A list that is present replaces the default. A JSON[]and a key with no text are “not given” and keep the default: to empty a list, clear it in code. - A map is written as one entry per name.
MaxConcurrentJobsPerLane:media=2limits themedialane;MaxConcurrentJobsPerLane=2names no lane and is refused, and the message shows the:<name>form. - An entry that cannot be read is named by its position (
Quotas:ThresholdPercents:1) or by its name (Scheduling:MaxConcurrentJobsPerLane:media). - Code that sets the option after binding wins. A value you assign in a
Configurecallback replaces the one from configuration, and a typo in the file that you have overridden in code does not stop the host. Writing the value the option already has is not told apart from leaving it.
dotnet user-secrets set "Tracon:Providers:OpenAI:ApiKey" "<value>"dotnet user-secrets set "Tracon:PostgreSql:ConnectionString" "<value>"Section index
Section titled “Section index”| Section | Option type | Registration that uses it |
|---|---|---|
Tracon |
TraconOptions |
AddTracon() |
Tracon:Approvals |
TraconApprovalOptions |
AddTracon() |
Tracon:AsyncRun |
TraconAsyncRunOptions |
AddTracon() |
Tracon:Canary |
CanaryOptions |
AddTracon() |
Tracon:ContentGuard |
TraconContentGuardOptions |
Guard pipeline after a guard is registered |
Tracon:ContentGuard:Pattern |
PatternContentGuardOptions |
Section presence or AddPatternContentGuard() |
Tracon:ContentProtection |
TraconContentProtectionOptions |
AddTracon() binds it; AddContentProtection() makes it apply |
Tracon:Drain |
TraconDrainOptions |
AddTracon() |
Tracon:Idempotency |
TraconIdempotencyOptions |
AddTracon() and the HTTP layer |
Tracon:InboundTriggers |
TraconInboundTriggerOptions |
AddTracon(); keys in Inbound triggers |
Tracon:Knowledge |
TraconKnowledgeOptions |
AddTracon(); PostgreSQL and embeddings make it functional |
Tracon:OnlineEvaluation |
OnlineEvaluationOptions |
AddTracon() plus at least one judge |
Tracon:Quotas |
TraconQuotaOptions |
AddTracon() |
Tracon:RateLimit |
TraconRateLimitOptions |
MapTracon() |
Tracon:Retention |
TraconRetentionOptions |
AddTracon() |
Tracon:RunContinuation |
TraconRunContinuationOptions |
AddTracon() |
Tracon:RunReconciliation |
RunReconciliationOptions |
AddTracon() |
Tracon:Scheduling |
TraconSchedulingOptions |
AddTracon(); UseScheduling() can override from code |
Tracon:SessionOwnership |
TraconSessionOwnershipOptions |
AddTracon(); keys in Sessions |
Tracon:SingletonExecution |
SingletonExecutionOptions |
AddTracon() |
Tracon:StructuredResponse |
TraconStructuredResponseOptions |
AddTracon() |
Tracon:TenantProviders |
TraconTenantProviderOptions |
AddTracon() |
Tracon:Webhooks |
TraconWebhookOptions |
AddTracon() |
Tracon:Workspace |
TraconWorkspaceOptions |
AddTracon() |
Tracon:Egress |
TraconEgressOptions |
AddTracon() |
Tracon:Providers:OpenAI |
OpenAIProviderOptions |
The configuration overload of UseOpenAI() |
Tracon:Providers:OpenAICompatible:{name} |
OpenAIProviderOptions shape |
The configuration overload of UseOpenAICompatible() |
Tracon:Providers:Anthropic |
AnthropicProviderOptions |
The configuration overload of UseAnthropic() |
Tracon:Providers:Google |
GoogleProviderOptions |
The configuration overload of UseGoogle() |
Tracon:Providers:AzureOpenAI |
AzureOpenAIProviderOptions |
The configuration overload of UseAzureOpenAI() |
Tracon:PostgreSql |
TraconPostgreSqlOptions |
The configuration overload of UsePostgreSql() |
Tracon:SqlServer |
TraconSqlServerOptions |
The configuration overload of UseSqlServer() |
Tracon:Sqlite |
TraconSqliteOptions |
The configuration overload of UseSqlite() |
Tracon:Mcp |
TraconMcpOptions (connection) and TraconMcpSecurityOptions (key prefix) |
UseMcp(); the prefix binds through AddTracon() |
Tracon:Workflows |
TraconWorkflowOptions |
UseWorkflows() |
Tracon:Voice |
VoiceOptions |
UseVoice() |
Tracon:Voice:Conversation |
VoiceConversationOptions |
The configuration overload of UseVoiceConversation() |
Tracon:Voice:Live |
VoiceLiveOptions |
The configuration overload of UseLiveVoice(); keys in Voice |
AddTracon() binds Skills:Scripts values but does not register a script runner.
Call UseSkillScripts() to cross that execution boundary; the call sets Enabled
and registers the runner. A settings section or grant record alone cannot execute a
script.
Core defaults under Tracon
Section titled “Core defaults under Tracon”Read by Tracon.Core through AddTracon(). No extra package reference.
Identity, validation, and agent graphs
Section titled “Identity, validation, and agent graphs”Key relative to Tracon |
Default | Meaning |
|---|---|---|
DefaultTenantId |
default |
Tenant used when no request resolver supplies one |
MaxParameterValueLength |
4096 bytes |
Largest UTF-8 size for one AgentParameter value in a run request or eval case |
Validation:McpTimeout |
5 seconds | Fresh MCP lookup limit during definition validation |
AgentGraph:MaxDepth |
3 |
Largest child-agent call depth; root depth is zero |
AgentGraph:MaxTotalTokens |
200000 |
Token budget shared by the whole call tree; enforced between model turns, mid-run |
AgentGraph:MaxTotalCost |
none | Cost budget shared by the whole call tree. It counts the token cost and the amounts that function nodes and tools reported beyond tokens; falls back to the token limit when a model’s price is undefined. Once spent, the next model call is refused and a workflow function node does not start |
AgentGraph:MaxTotalRuns |
25 |
Largest child-run count; the root does not count |
AgentGraph:MaxDuration |
none | Wall-clock budget for the whole call tree, counted from the root run’s start. Once passed, the next model call is refused and a workflow function node does not start; a call or node already running is not stopped |
AgentGraph:ChildDeadline |
2 minutes | Longest one sub-agent call, or one agent step of a workflow, may take before it is cancelled (the cooperative layer). A workflow agent step can carry its own timeout, which replaces this value for that step. From 1 millisecond to about 49.7 days |
AgentGraph:WaitTimeout |
ChildDeadline plus 30 seconds |
Hard cutoff for a call that ignores cancellation. Must be greater than ChildDeadline; when unset it follows it |
UtilityModel |
null |
Optional model binding for compaction summarization. Provider and Model are both required, or no binding is built. A Temperature, TopP or MaxOutputTokens that is not a number stops the host at startup; an empty one means the provider default |
Tools:DefaultTimeout |
30 seconds | Longest one tool call may run when its own registration sets no timeout |
Tools:DefaultMaxOutputBytes |
null (unlimited) |
UTF-8 byte limit for a tool result when its own registration sets none; must be at least 57 bytes when set |
Non-positive graph token, cost, or run limits remove that limit. See
TraconAgentGraphOptions
for the exact runtime interpretation.
Skills and script execution
Section titled “Skills and script execution”| Key | Default |
|---|---|
Skills:MaxSkillsPerAgent |
10 |
Skills:MaxInstructionsLength |
65536 bytes |
Skills:MaxResourceContentLength |
262144 bytes per resource |
Skills:MaxResourcesPerSkill |
20 |
Skills:Scripts:Enabled |
false |
Skills:Scripts:PlatformIsolationAcknowledged |
false |
Skills:Scripts:AllowStoredScripts |
false |
Skills:Scripts:SkillRoots |
Empty |
Skills:Scripts:Interpreters |
Empty; therefore no script can start |
Skills:Scripts:EnvironmentAllowList |
PATH, HOME |
Skills:Scripts:Timeout |
30 seconds |
Skills:Scripts:MaxOutputBytes |
262144 |
Skills:Scripts:MaxArgumentBytes |
16384 |
Skills:Scripts:MaxScriptContentLength |
65536 |
Skills:Scripts:MaxScriptsPerSkill |
10 |
Skills:Scripts:MaxConcurrentPerTenant |
2 |
Skills:Scripts:MaxConcurrentTotal |
8 |
Skills:Scripts:SearchDepth |
2 |
Enabled=true is invalid until PlatformIsolationAcknowledged=true. Tracon
does not provide a filesystem, network, CPU, memory, or privilege sandbox. The
environment allowlist only stops a script from inheriting variables: the script
still runs as the same operating-system user and reads what that user can read.
Attachments and audit
Section titled “Attachments and audit”| Key | Default |
|---|---|
Attachments:MaxBytes |
20971520 bytes, or 20 MiB |
Attachments:AllowedMediaTypes |
image/png, image/jpeg, image/webp, image/gif, application/pdf, text/plain, audio/* |
Audit:ActorClaimType |
null; resolution tries name identifier, name, then sub |
The attachment guard checks file signatures. It does not trust the client’s
Content-Type header.
Provider resilience and health
Section titled “Provider resilience and health”| Key | Default |
|---|---|
CircuitBreaker:Enabled |
true |
CircuitBreaker:FailureThreshold |
5 consecutive failures |
CircuitBreaker:BreakDuration |
30 seconds |
Health:CacheTtl |
60 seconds |
Health:BackgroundInterval |
null; no background provider polling |
The on-demand model-health endpoint can still refresh a provider while background polling is off.
Model fallback and outgoing concurrency
Section titled “Model fallback and outgoing concurrency”| Key | Default |
|---|---|
Preflight:Enabled |
false |
Preflight:ReserveRatio |
0.2 |
ModelConcurrency:MaxConcurrentCallsPerProvider |
null, unlimited |
Preflight governs the inline pre-flight check on POST /api/agents/{name}/run;
POST /api/agents/{name}/estimate reports the same numbers regardless of this
flag. ModelBinding.Fallbacks (the fallback chain itself) is per-agent, defined
on the model binding, not a global setting. See
Reliable runs and
Model providers.
Observability
Section titled “Observability”| Key | Default |
|---|---|
Observability:Enabled |
true |
Observability:PersistSpans |
true |
Observability:SuccessSampleRatio |
0.1 |
Observability:AlwaysPersistFailures |
true |
Observability:MaxSpansPerRun |
200 |
Observability:RecordSensitiveData |
false |
Observability:IncludeAgentVersionTag |
true |
Observability:IncludeTenantTag |
false |
Observability:EnableQuotaUsageGauge |
false |
Observability:QuotaUsageRefreshInterval |
30 seconds |
Observability:EnableJobQueueDepthGauge |
false |
Observability:JobQueueDepthRefreshInterval |
30 seconds |
Observability:MaxJobLaneCardinality |
64 |
These settings control Tracon span creation and its own trace store. They do not replace the application’s OpenTelemetry exporter.
IncludeTenantTag adds tracon.tenant.id to eight metrics (run, cost, judge,
response cache, audit failures, recording failures and jobs). It is off by default,
because it multiplies each series by the number of tenants. Spans and the quota
gauges always carry the tenant. A value other than true or false stops startup.
See the tenant tag on metrics.
Both gauges are off by default because each one reads the database. When a gauge
is on, a background refresh reads it at startup and then once per matching
refresh interval, and a collection only reads the last result. Turning a gauge on,
or changing its interval, takes effect at the next start. An enabled gauge needs a
refresh interval from one millisecond to about 49.7 days, or startup validation
fails.
MaxJobLaneCardinality bounds how many distinct job lanes get a metric series of
their own before the rest are folded into a single other series — see
observability.
Run recording
Section titled “Run recording”| Key | Default |
|---|---|
RunRecording:Enabled |
true |
RunRecording:RecordMessageDeltas |
true |
RunRecording:RecordToolPayloads |
true |
RunRecording:MaxPayloadLength |
8192 characters |
RunRecording:RecordRunInput |
true |
Disable tool payloads when they can contain personal or regulated data. Replay needs
recorded run input, and so does continuing a parameterized run: the parameter values a
run was bound with are recorded beside its input, and a replay, an automatic continuation,
a resume after a tool approval or a resume of a workflow that declares parameters is
refused when RecordRunInput was off for the original run. A store failure is logged and never blocks the agent response, so
recording is best-effort during a storage outage.
Session workspace limits
Section titled “Session workspace limits”| Key | Default |
|---|---|
Workspace:MaxFileBytes |
262144 (256 KiB) |
Workspace:MaxSessionBytes |
5242880 (5 MiB) |
Workspace:MaxTenantBytes |
524288000 (500 MiB) |
The limits apply to an agent whose definition turns workspace.enabled on. A write that would
pass one is refused and the model reads “Workspace quota reached”. Each value is at least 1, a session limit
is not below the file limit, and a tenant limit is not below the session limit; the application refuses
to start otherwise. A file counts 1 KiB more than its content in the limit of a session and of a tenant, for its row. The limits are soft, and a SQL Server store counts two bytes for each ASCII character.
See Give an agent files in each session.
Structured response validation
Section titled “Structured response validation”| Key | Default |
|---|---|
StructuredResponse:Enabled |
false |
StructuredResponse:MaxRepairAttempts |
0 |
Off by default: a response is never inspected after the model returns it. Applies only
to an agent whose ResponseFormat.Kind is Json or JsonSchema. See
Validate the response.
MaxRepairAttempts is off by default too: a value of 0 fails the run on the first
invalid response, exactly as when repair does not exist. A value of 2 permits at
most three model calls in total — the original turn plus two repairs — all inside the
same run, under the same budget. See
Let the model repair a rejected response.
Pricing
Section titled “Pricing”Pricing has no built-in values. Currency, provider/model token prices, and voice
and image prices all start empty. The supported shape is:
Tracon:Pricing:CurrencyTracon:Pricing:{provider}:{model}:InputTracon:Pricing:{provider}:{model}:OutputTracon:Pricing:{provider}:{model}:CachedInputTracon:Pricing:Voice:{provider}:{model}:PerMillionCharactersTracon:Pricing:Voice:{provider}:{model}:PerMinuteTracon:Pricing:Images:{provider}:{model}:PerImageTracon:Pricing:Images:{provider}:{model}:SizeMultipliers:{provider-size}Tracon:Pricing:Images:{provider}:{model}:OutputCostPerMillionTokensTracon:Pricing:HostedTools:{provider}:{kind}:PerCallHostedTools prices the calls of a hosted tool. The {provider} is the one that ran
the call (openai-responses, anthropic, google), and {kind} is WebSearch, CodeInterpreter, or
FileSearch; a name that is none of them stops the host at start. A kind with no price is listed on the
run and not added to its cost; Tracon never prices it at zero.
Values label and calculate reports only. Tracon performs no currency conversion, so
Currency also decides which reported amounts add up: an amount that a workflow function node or a
tool reported beyond tokens joins the run’s non-token total only when it is in this
currency (an amount that names no currency is in it, and with no Currency set only such
an amount adds); any other is listed and counted as not added. A function node’s amounts
are the amounts the node computed, not a price table Tracon applies.
The shorter configuration keys Input, Output and CachedInput bind to the code
properties InputCostPerMillionTokens, OutputCostPerMillionTokens and
CachedInputCostPerMillionTokens.
CachedInput is the rate for input tokens the provider served from its prompt
cache. It is optional, and its absence is not a configuration error — unlike
Input and Output, where an entry with neither is rejected at startup as a
likely typo.
Cost is computed by subtraction, because a provider counts cached tokens inside the input total rather than beside it:
full_price_input = InputTokens - CachedInputTokenscost = full_price_input * Input + CachedInputTokens * CachedInput + OutputTokens * OutputReasoning tokens are recorded (reasoningTokens) but priced at the output rate:
providers do not bill them separately today, and an unmeasured distinction is not
worth widening the price schema.
An image model uses either PerImage or OutputCostPerMillionTokens, never both.
SizeMultipliers applies only to a per-image price and uses the exact provider size
string, for example 1024x1024. An image response with no matching configured price
records its real quantity but leaves cost as null; Tracon does not estimate
image prices.
Images
Section titled “Images”Tracon:Images is off by default (false). When Enabled is true, Provider and
Model are required and MaxImagesPerRequest must be at least one. Enabling it adds
the generate_image tool and maps POST /api/images/generate.
Timeout bounds one generate_image call and defaults to 00:02:00,
not the 30 second Tracon:Tools:DefaultTimeout every other tool inherits. Image
generation is slower than the tool the generic default was chosen for: a measured
gpt-image-1 request routinely needs 30 to 35 seconds, so the generic bound cut off
a call that was about to succeed. Shorten it if you would rather fail fast — a call
that outlives it is cancelled, and if the provider finishes anyway the spend is still
recorded against the original call.
{ "Tracon": { "Images": { "Enabled": true, "Provider": "openai", "Model": "gpt-image-1", "MaxImagesPerRequest": 1, "Timeout": "00:02:00" }, "Pricing": { "Currency": "USD", "Images": { "openai": { "gpt-image-1": { "PerImage": 0.04, "SizeMultipliers": { "1024x1024": 2.0 } } } } } }}Provider extensions set Provider when it is empty. Set it explicitly when the host
registers more than one image provider or a custom keyed generator.
Operational sections
Section titled “Operational sections”Read by Tracon.Core. The lease-backed entries coordinate more than one process only with a SQL persistence package.
Scheduling, async runs, leases, and recovery
Section titled “Scheduling, async runs, leases, and recovery”| Section and key | Default |
|---|---|
Scheduling:Enabled |
true |
Scheduling:RunWorker |
true |
Scheduling:MaxConcurrentJobs |
2 |
Scheduling:PollInterval |
10 seconds |
Scheduling:LeaseDuration |
5 minutes |
Scheduling:MaxAttempts |
3 |
Scheduling:MaxDurationByHandlerKey |
empty; each attempt’s time limit per handler key, 1 ms to about 49.7 days. A job’s own maxDuration wins; a key not listed has no limit. A value out of range fails at startup |
Scheduling:MaxItemsPerJob |
1000 |
Scheduling:Lanes |
null; leases from every lane |
Scheduling:MaxConcurrentJobsPerLane |
empty; a lane not listed shares MaxConcurrentJobs. A value that is not a number fails at startup |
Scheduling:LaneByHandlerKey |
empty; maps a handler key to a lane when the caller left it unset |
Scheduling:HttpSchedulableHandlerKeys |
empty; the handler keys PUT /api/schedules/{name} accepts. Empty means the built-in keys; a non-empty list replaces that default rather than extending it |
AsyncRun:Enabled |
true |
AsyncRun:MaxAttempts |
1 |
SingletonExecution:Enabled |
false |
SingletonExecution:LeaseDuration |
60 seconds; at least 3 seconds while SingletonExecution:Enabled is true |
SingletonExecution:OwnerId |
null; generated by the runtime |
RunReconciliation:Enabled |
false |
RunReconciliation:HeartbeatInterval |
30 seconds |
RunReconciliation:OrphanThreshold |
5 minutes |
RunReconciliation:ScanInterval |
1 minute |
RunReconciliation:MaxRunsPerScan |
100 |
RunContinuation:Enabled |
false; has no effect unless RunReconciliation:Enabled is also true |
RunContinuation:MaxAttempts |
1 |
Drain:Enabled |
false |
Drain:Timeout |
30 seconds |
UseScheduling() changes worker settings from code; it does not create a second
queue. AddTracon() already registers the core job contracts.
Every interval that drives a background timer must be between 1 millisecond and about
49.7 days, the .NET timer range: Scheduling:PollInterval,
RunReconciliation:HeartbeatInterval, RunReconciliation:ScanInterval,
Approvals:ScanInterval, Canary:ScanInterval, Health:BackgroundInterval,
Mcp:RefreshInterval, and the two Observability gauge intervals. A lease renews at a
third of its length, so Scheduling:LeaseDuration and SingletonExecution:LeaseDuration
may each be at most about 149 days. A value outside its range fails at
startup and names the option. Each of these is checked only while the feature that owns
its timer is on. Retention:BatchDelay may be zero and is always held to at most about
49.7 days.
Approvals, evaluation, and canaries
Section titled “Approvals, evaluation, and canaries”| Section and key | Default |
|---|---|
Approvals:DefaultExpiration |
24 hours |
Approvals:ExpirationEnabled |
true |
Approvals:ScanInterval |
1 minute |
Approvals:MaxPerScan |
100 |
OnlineEvaluation:Enabled |
false |
OnlineEvaluation:SampleRate |
0 |
OnlineEvaluation:MaxScoresPerHour |
100 |
OnlineEvaluation:AgentNames |
Empty; all agents are eligible |
OnlineEvaluation:LowScoreThreshold |
60 |
OnlineEvaluation:MinSampleSize |
20 |
OnlineEvaluation:JudgeTimeout |
60 seconds per judge call |
OnlineEvaluation:EvaluationWindow |
1 hour |
Canary:AutoRollbackEnabled |
false |
Canary:ScanInterval |
5 minutes |
Online evaluation needs both Enabled=true, a positive sample rate, and a registered
IRunJudge. AddModelRunJudge() registers the built-in model-backed judge but does
not enable sampling.
Admission, guards, and knowledge
Section titled “Admission, guards, and knowledge”| Section and key | Default |
|---|---|
Quotas:Enabled |
true; the rule set starts empty |
Quotas:TimeZone |
UTC |
Quotas:ThresholdPercents |
80, 100. A value outside 1–100 or not a number fails at startup |
Quotas:AllowOnStoreFailure |
true |
Quotas:PublishThresholdToRunStream |
false |
RateLimit:Enabled |
false |
RateLimit:PermitLimit |
60 |
RateLimit:Window |
1 minute |
RateLimit:QueueLimit |
0 |
RateLimit:Partition |
Tenant |
Idempotency:Enabled |
true |
Idempotency:MaxKeyLength |
255 |
ContentGuard:InspectInput |
true |
ContentGuard:InspectOutput |
true |
ContentGuard:BufferStreamingOutput |
true |
ContentGuard:Pattern:DeniedTerms |
Empty |
ContentGuard:Pattern:MaskedPii |
None; comma-separated names, empty means none. A name it does not know fails at startup |
ContentGuard:Pattern:MaskReplacement |
[redacted] |
Knowledge:Dimensions |
1536 |
Knowledge:ChunkSize |
1000 characters |
Knowledge:ChunkOverlap |
100 characters |
Knowledge:MaxResults |
5 |
Quota enforcement with no stored rule rejects nothing. Pattern settings do no work until the built-in guard is registered; a present Pattern section is itself a registration signal. Knowledge stays unavailable until both the vector store and an embedding generator exist.
Outbound network targets
Section titled “Outbound network targets”Key relative to Tracon:Egress |
Default |
|---|---|
AllowPrivateNetworkTargets |
false |
Covers all three surfaces that reach the network: webhook delivery, MCP server connections, and per-tenant model provider endpoints. While it is off, a target that resolves to a private network address is refused — at save time for an address written as an IP literal, and on every connection for one written as a host name. See Security.
Webhooks
Section titled “Webhooks”Key relative to Tracon:Webhooks |
Default |
|---|---|
Enabled |
true |
AllowPrivateNetworkTargets |
false |
AllowInsecureHttp |
false |
AllowedConfigurationPrefix |
Tracon:WebhookSecrets: |
MaxExtraHeaders |
20 |
Timeout |
10 seconds |
MaxResponseBytes |
8192 |
DisableAfterConsecutiveFailures |
20 |
RetryDelays |
1 minute, 5 minutes, 30 minutes, 2 hours, 6 hours. A delay that is not above zero or not a time span fails at startup |
SignatureTolerance |
5 minutes |
No request is sent while no subscription exists. Private targets, insecure HTTP, and redirects remain blocked by default.
AllowedConfigurationPrefix bounds which configuration key a subscription may name as
its signing secret. Inside it, a tenant’s subscription names {prefix}{tenant}:...
and a flat name belongs to the default tenant; any other name is refused both when the
subscription is saved and when the secret is resolved. MaxExtraHeaders bounds a subscription’s own extra
headers — headers whose name Tracon sets itself are always dropped, whatever the
limit is. AllowPrivateNetworkTargets here applies to webhook delivery only; the
shared Tracon:Egress setting covers this surface too, and either one being on is
enough.
At-rest content protection
Section titled “At-rest content protection”Key relative to Tracon:ContentProtection |
Default |
|---|---|
Enabled |
false |
ActiveKeyId |
(none) |
Keys |
Empty. An entry with an empty name fails at startup |
Columns |
All twelve protected columns. A name that is not a protected column fails at startup |
Encryption is off until both AddContentProtection(...) is called and Enabled is
true. Keys maps a key id to the name of another configuration key — never to
the key’s raw value — the same indirection
other configuration keys
use elsewhere. See
at-rest content protection
for the full key setup and its limits.
The Keys and Columns checks run while Enabled is false too: rows encrypted
earlier are still read through Keys after protection is turned off. A Columns
list replaces the default; an empty one keeps every column.
Retention defaults
Section titled “Retention defaults”Read by Tracon.Core. Deletion needs a persistence package; the in-memory stores have nothing to retain across a restart.
Tracon:Retention:Enabled defaults to false. BatchSize defaults to 5000
and BatchDelay to 100 ms. The following ages become configuration-based defaults
only after retention is enabled. A database policy for a target takes precedence.
| Child key | Default MaxAgeDays |
Archive default |
|---|---|---|
RunEvents |
30 days; a waiting workflow’s request is kept | false |
ToolInvocations |
90 days | false |
Spans |
14 days | false |
Jobs |
30 days; completed jobs only | false |
WebhookDeliveries |
7 days; delivered rows only | false |
EvalCaseResults |
180 days | false |
WorkflowCheckpoints |
7 days after completion; a waiting workflow’s are kept | false |
SkillScriptGrants |
30 days after expiry or revocation | false |
Attachments |
7 days for orphaned rows: no session, and no waiting, running, or recently finished workflow run with the session id; stored bytes go first | false |
Sessions |
Disabled, null |
false |
Conversations |
Disabled, null |
false |
IdempotencyKeys |
1 day | false |
RunInputs |
30 days; a waiting workflow’s row is kept | false |
VoiceSessions |
30 days | false |
RunScores |
180 days | false |
DocumentEmbeddings |
Disabled, null |
false |
WorkflowRequests |
30 days after the request expired; closed rows only | false |
A workflow run waiting for a human answer (AwaitingInput) keeps its pending
request event, its checkpoints and its run input row for as long as it waits,
whatever their age: the request lives only in that event, the answer resumes from those
checkpoints, and the parameter values it resumes with live only in that row. A
request timeout is what ends
the wait: when it passes, the run is closed and the next retention round deletes those
rows by age like any other.
MaxAgeDays takes a whole number of days, and a value below 1 fails at startup.
Configuration cannot switch off a target that has a default age: an empty value or a
JSON null leaves the default in place. To switch one off, save a disabled retention
policy for it, or set its MaxAgeDays to null in
Configure<TraconRetentionOptions>(...).
Persistence sections
Section titled “Persistence sections”Read by Tracon.PostgreSql, Tracon.SqlServer, and Tracon.Sqlite. A section without its package does nothing.
| Section | Key | Default |
|---|---|---|
Tracon:PostgreSql |
ConnectionString |
null; required by the configuration registration |
SchemaName |
tracon |
|
AutoApplyMigrations |
true |
|
CommandTimeoutSeconds |
30 |
|
Tracon:SqlServer |
ConnectionString |
null; required by the configuration registration |
SchemaName |
tracon |
|
AutoApplyMigrations |
true |
|
CommandTimeoutSeconds |
30 |
|
Tracon:Sqlite |
ConnectionString |
null; required by the configuration registration |
TablePrefix |
tracon_ |
|
AutoApplyMigrations |
true |
|
CommandTimeoutSeconds |
30 |
SQLite rejects bare Data Source=:memory:. Use a shared in-memory URI when a file is
not suitable. PostgreSQL and SQL Server use a schema; SQLite uses a table prefix.
Provider sections
Section titled “Provider sections”Read by Tracon.OpenAI, Tracon.Anthropic, Tracon.Google, and Tracon.AzureOpenAI, each through its own Use*() call.
All provider model lists start empty. All nullable request timeouts use the provider library default.
| Section | Verified defaults |
|---|---|
Tracon:Providers:OpenAI |
ApiKey=null, DefaultModel=null, Endpoint=null for OpenAI, Organization=null, Timeout=null, Models=[] |
Tracon:Providers:OpenAICompatible:{name} |
Same shape as OpenAI; EnableResponsesSurface=false |
Tracon:Providers:Anthropic |
ApiKey=null, DefaultModel=null, Endpoint=null for Anthropic, DefaultMaxOutputTokens=4096, Timeout=null, MaxRetries=null, Models=[] |
Tracon:Providers:Google |
ApiKey=null, DefaultModel=null, Endpoint=null for Google, ApiVersion=null, Timeout=null, Models=[] |
Tracon:Providers:AzureOpenAI |
Endpoint=null but required, ApiKey=null, CredentialFactory=null, DefaultDeployment=null, Audience=null for public cloud, Timeout=null, Models=[] |
CredentialFactory is code-only because it is a delegate. When it is set, Azure does
not use ApiKey. The consumer chooses and references Azure.Identity when managed
identity is required.
Each Models entry binds every ModelDescriptor field: Name, DisplayName,
ContextWindowTokens, MaxOutputTokens, SupportsStreaming (true),
SupportsTools (true), SupportsReasoning (false), SupportsStructuredOutput
(false), SupportsSampling (null), and the three *CostPerMillionTokens prices.
SupportsSampling = false makes a definition that sets Temperature or TopP fail
to compile. MaxOutputTokens lets the validation report warn when a binding leaves
its own limit to a lower provider default, such as Anthropic’s
DefaultMaxOutputTokens. See
the model catalog.
{ "Tracon": { "Providers": { "Anthropic": { "DefaultMaxOutputTokens": 4096, "Models": [ { "Name": "your-current-claude-model", "MaxOutputTokens": 128000, "SupportsStructuredOutput": true, "SupportsSampling": false } ] } } }}| Tracon:TenantProviders | AllowedConfigurationPrefix="Tracon:ProviderKeys:" |
A tenant provider binding’s configuration key name must start with
AllowedConfigurationPrefix followed by the tenant’s segment
(Tracon:ProviderKeys:acme:...); a flat name belongs to the default tenant. Any other
name is rejected with 400, both when the binding is saved and again when it is
resolved. See
Per-tenant credentials.
MCP, workflows, and voice
Section titled “MCP, workflows, and voice”Read by Tracon.Mcp, Tracon.Workflows, and Tracon.Voice. Live conversation is the exception: it is in Tracon.Core, behind UseVoiceConversation().
MCP client
Section titled “MCP client”Key relative to Tracon:Mcp |
Default |
|---|---|
Enabled |
true |
RefreshInterval |
5 minutes |
StaleToolRetention |
15 minutes |
ConnectionTimeout |
30 seconds |
MaxToolsPerServer |
100 |
MaxResourceBytesPerResource |
65536 |
MaxResourceBytesTotal |
262144 |
OAuthCallbackBaseUri |
null |
AllowedConfigurationPrefix |
Tracon:McpSecrets: |
AllowedConfigurationPrefix belongs to TraconMcpSecurityOptions rather than
TraconMcpOptions, and binds through AddTracon() — the rule is enforced
both where a server definition is saved and where its key is resolved, and those two
live in packages that do not reference each other. The section name is the same, so
it stays one section to configure. It bounds both headerConfigurationKeys and
oauthClientSecretConfigurationKey, and inside it a tenant’s server names
{prefix}{tenant}:...; a flat name belongs to the default tenant.
The remaining keys belong to TraconMcpOptions. UseMcp() without arguments uses
those defaults but does not read IConfiguration implicitly. Use the explicit overload when you want the section:
tracon.UseMcp( builder.Configuration.GetSection(TraconMcpOptions.SectionName), configure: null);Workflows
Section titled “Workflows”Key relative to Tracon:Workflows |
Default |
|---|---|
Enabled |
true |
EnableCheckpointing |
true |
MaxConcurrentRuns |
4 |
MaxConcurrentRunsPerTenant |
null; no per-tenant limit. When set, from 1 to MaxConcurrentRuns |
RunTimeout |
10 minutes |
MaxRunTimeout |
null; a definition’s runTimeout may then only shorten RunTimeout |
MaxSuperSteps |
100 |
MaxNodeSettingsLength |
16384 bytes |
KeepCheckpointsAfterCompletion |
true |
RequestExpirationScanInterval |
1 minute |
MaxRequestExpirationsPerScan |
100 |
MaxConcurrentRunsPerTenant limits how many runs one tenant has going at the same time,
in each process and, for queued workflow jobs, in the job queue (a soft count across
processes). See How many runs go at once.
The section does not register the execution engine. Call UseWorkflows(); that call
binds this section and then applies its optional code override.
MaxRunTimeout is the longest run timeout a workflow definition may set. A save above
it, or above RunTimeout while it is unset, is refused with 400. A workflow defined in code
sets it with WorkflowRegistrationOptions.RunTimeout; a value above the ceiling stops the host at
startup, naming the workflow, while Enabled is true. It must be at least
RunTimeout and fails at startup otherwise, even while Enabled is false. A
stored definition above a ceiling that was lowered later runs with the ceiling, and a
warning is logged.
MaxNodeSettingsLength caps the JSON text of one function node’s settings when a
workflow is saved; a definition stored before the cap was lowered still runs.
RequestExpirationScanInterval is how often the scan that closes the runs of expired
workflow requests looks; it must be
from one millisecond to about 49.7 days and fails at startup otherwise, while Enabled is
true. MaxRequestExpirationsPerScan must be at least 1.
Speech tools
Section titled “Speech tools”Key relative to Tracon:Voice |
Default |
|---|---|
Provider |
elevenlabs |
ApiKey |
null |
Endpoint |
null; provider public endpoint |
DefaultVoiceId |
null |
SynthesisModelId |
null |
TranscriptionModelId |
null |
DialogueModelId |
null; the provider’s default dialogue model |
OutputFormat |
mp3_44100_128 |
MaxCharactersPerRequest |
5000 |
MaxDialogueCharactersPerRequest |
2000 |
MaxConcurrentRequests |
2 |
RequireApproval |
false |
Timeout |
null; implementation uses 100 seconds |
The section is validated when the application starts. Provider, ApiKey and
Endpoint configure only the built-in ElevenLabs client; elevenlabs is the only
Provider value. When your own ISpeechSynthesizer and ISpeechTranscriber are
registered before UseVoice(), those three are not required. Provider is not a
price key: Tracon:Pricing:Voice is keyed by the ProviderName of the implementation
that did the work. MaxCharactersPerRequest is the built-in client’s limit; your own
synthesizer reports its limit through ISpeechSynthesizer.MaxCharactersPerRequest.
DialogueModelId and MaxDialogueCharactersPerRequest apply to a dialogue voiced by
the built-in client. The single-voice SynthesisModelId is never sent for a
dialogue. MaxDialogueCharactersPerRequest must be greater than zero; a longer
dialogue is refused, not split, and the built-in client reports the value through
ISpeechDialogueSynthesizer.DialogueCapabilities. Synthesis, dialogue and
transcription share the one MaxConcurrentRequests limit.
Voice conversation
Section titled “Voice conversation”Key relative to Tracon:Voice:Conversation |
Default |
|---|---|
MaxConcurrentConnectionsPerTenant |
5 |
MaxConnectionDuration |
30 minutes |
IdleTimeout |
2 minutes |
MaxUtteranceDuration |
60 seconds |
MaxUtteranceBytes |
8388608 |
PersistAudio |
false |
VoiceId |
null |
OutputMediaType |
audio/mpeg |
InputSampleRate |
16000 Hz |
MaxSpokenCharactersPerTurn |
5000 |
The WebSocket route does not exist until UseVoiceConversation() is called. A ready
conversation also needs both ISpeechTranscriber and ISpeechSynthesizer.
Endpoint options are code-only
Section titled “Endpoint options are code-only”Read by Tracon.AspNetCore at the MapTracon() call, not from configuration.
TraconEndpointOptions belongs to the MapTracon() call. It has no named
configuration section.
| Option | Default |
|---|---|
AllowRemoteAccess |
false |
AuthToken |
null |
AuthorizationPolicy |
null |
RequireRolePolicies |
false |
EnableDiagnosticsEndpoint |
false |
MapOpenAIConversations |
true |
RunEventPollInterval |
250 ms |
StreamKeepAliveInterval |
15 seconds |
AllowedOrigins |
empty (no CORS header sent) |
app.MapTracon("/tracon", options =>{ options.AllowRemoteAccess = true; options.AuthToken = builder.Configuration["Tracon:AuthToken"]; options.EnableDiagnosticsEndpoint = true; options.RequireAuthorization("TraconAccess");});MapOpenAIConversations is the only one that starts on (true). Setting it to false
leaves the four /v1/conversations routes unmapped: they answer 404 and
disappear from the OpenAPI document, while /v1/responses and
/v1/chat/completions are unaffected. It shrinks the surface a deployment that
never calls those routes exposes; it is not a security control, since the
routes go through the same role policies, API key scopes, session ownership and
IRunAuthorizationHandler gate as /api/sessions.
StreamKeepAliveInterval is the longest a streaming response (an agent or
workflow run, a resume or answer, the OpenAI-compatible endpoints) stays
silent: when nothing else was written for that long, it writes an SSE comment
line, which SSE readers skip. A reader with an idle limit takes a silent
stream for a dead connection and closes it, and a closed connection cancels the
run. Keep the value below the shortest idle timeout between the server and its
readers - a reverse proxy’s read timeout - and below 30 seconds while the
console is in use.
Do not enable remote access without a token, API key, or authorization policy: with
none of them configured, an anonymous remote request receives 401, and an anonymous
local request with a non-loopback Host or Origin receives 403. Behind a reverse
proxy, configure forwarded headers and do not treat the proxy’s loopback address as a
security boundary; a request that still carries X-Forwarded-For, Forwarded, or
X-Real-IP counts as remote. Set RequireRolePolicies=true only after
you register the Reader, Operator, and Admin policies; otherwise mapping fails at
startup by design.
Options without a named section
Section titled “Options without a named section”Read at registration time by the package that owns each call. None of them can be set from a settings file.
The following features use explicit code options because they contain delegates, freeze an exposure allowlist at registration, or define request-resolution policy:
-
UseTenancy(TraconTenancyOptions)selects the claim or explicitly allowed header resolver. Four properties decide how a request’s tenant is resolved, and the default of each is the safe one:Property Default What it does EnabledfalseMulti-tenancy is off until you turn it on; every request then resolves a tenant ClaimType(none) The claim the resolver reads from the authenticated principal. Left unset, no claim is read at all — set it explicitly, for example to tenant_idAllowHeaderResolutionfalseWhether X-Tracon-Tenantmay name the tenant. Leave this off in production unless a trusted gateway sets the header and strips any client copyHeaderNameX-Tracon-TenantThe header consulted when header resolution is on AllowedTenantsempty When populated, an allowlist: a resolved tenant outside it is rejected rather than served -
UseMcpServer(TraconMcpServerOptions)exposes no agent by default (false). -
UseA2A(TraconA2AOptions)exposes no agent by default. -
AddModelRunJudge(ModelRunJudgeOptions)defines the judge model and itsCriteria: the plain-language standard the judge scores a run against. -
AddAgent(),AddSkill(),AddWorkflow(), andAddEvalCheck()define executable or compiled behavior. -
IDataSubjectResolver(services.AddSingleton<IDataSubjectResolver, ...>()) maps a data subject id to their sessions, runs, and conversations — no default implementation, no configuration section; see Data subject rights.
Use the API reference for every property on these code-only types. Their absence from this section table is deliberate.
Read next
Section titled “Read next”- Securing the endpoints — the options above that decide who can call what
- Production deployment — which of these you set differently per environment
- Troubleshooting — what a wrong value looks like at run time