Reference
Versions and upgrades
Tracon is a pre-1.0 package family. Treat version selection as part of your application architecture, not as a restore detail.
The release process produces 21 NuGet packages and one npm package (@tracon/client), all
cut from the same v* tag and sharing one version line: there is no split between
a stable subset and a preview subset. The public surface carries no compatibility
promise for as long as that line stays below 1.0.0-rc.1 - a narrowing or a reshaped
type is not treated as a breaking change until the family reaches that release.
Release notes
Section titled “Release notes”Every published version has a dated entry on the Release
notes page, grouped as Added, Changed, Deprecated,
Removed, Fixed, and Security. Each package’s PackageReleaseNotes metadata
links to the entry for the exact version you installed.
The entry names, by its exact name, every public type that was removed or
changed since the previous published version, and every target framework a
package no longer ships. The release process checks this against a
machine-made list: it validates each package against the previous published
package, and it does not publish when the notes leave out a name. A narrowing
is still allowed before 1.0.0-rc.1; an unannounced one is not. From
1.0.0-rc.1 even an announced one is not: see What 1.x promises for the .NET
API and What 1.x promises for HTTP,
telemetry, configuration, error codes and the
CLI.
What 1.x promises for the .NET API
Section titled “What 1.x promises for the .NET API”Tracon freezes the public .NET API at 1.0.0-rc.1. From that release on, each
change to a public type or member belongs to one SemVer class. The release
process reads the public API and rejects a release that puts such a change in a
class that does not allow it. Behavior is a different matter: two rows of the
table are a maintainer’s review, and the release process only makes them visible
(see below). Until rc.1 the earlier rule holds: a break is allowed when the
release notes name it.
| Change | Patch | Minor | Major |
|---|---|---|---|
| A new public type | No | Yes | Yes |
| A new public member on an existing type (optional, with a documented default) | No | Yes | Yes |
| A new interface member with a default body | No | Yes | Yes |
| A new interface member without a body | No | No | Yes |
| A new abstract member on an abstract class | No | No | Yes |
A new required member on an existing type |
No | No | Yes |
A required member becomes optional |
No | Yes | Yes |
| A new positional parameter on a record, or a new optional parameter on a method | No | No (a new overload: Yes) | Yes |
| A new enum value | No | Yes | Yes |
| An enum value removed, or its number changed | No | No | Yes |
| A public type or member removed, renamed, or given another signature | No | No | Yes |
| A target framework dropped | No | No | Yes |
A new test in Tracon.Testing.Contracts.Xunit that measures behavior the documentation already states |
Yes (a defect fix) | Yes | Yes |
A new test in Tracon.Testing.Contracts.Xunit that asks for new behavior |
No | No | Yes |
| A change to behavior that the XML documentation states | No | No | Yes |
How the release process holds each row:
- A frozen release rejects a break. When the last published version is
1.0.0-rc.1or later and the new version has the same major version, a removed type or member, a changed signature, a dropped target framework, an interface member without a body, an abstract member, an enum value that is gone or renumbered, and arequiredmember that an existing type gains all stop the release. The release notes do not change that. A new major version is the one place where a break is allowed, and the notes must name it. - A patch release does not grow the surface. It compares the public API
files with those of the last published version, and any added line stops
the release. The one exception is a new contract test (below). A
requiredmember that becomes optional or goes away stops a patch as well. - Between
1.0.0-rc.1and1.0.0the surface only closes. A release with the same major and minor version as the last published one counts as a patch:1.0.0-rc.2and1.0.0add no public member to1.0.0-rc.1. - A
requiredmember is checked apart. The compatibility check of the .NET SDK does not report arequiredmember added to an existing type. The repository keeps a list of every publicrequiredmember, a test keeps the list true to the code, and the release process compares it with the list at the last published version. - Every run prints its rule. The first line of the check says whether the release is judged as a preview, a frozen release, or a new major version.
- Behavior is reviewed, not read. The release process cannot tell whether a new contract test asks for new behavior, or whether a change alters behavior that the XML documentation states. It lists every new contract test and stops when the release notes do not name one; the maintainer judges the rest.
Three more rules complete the table:
- Your code handles an enum value it does not know. A
switchover a Tracon enum has adefaultbranch. Tracon adds a value in a minor release. - One rule covers every public interface. An interface that Tracon calls
and you never implement, such as
IToolRegistryorIWorkflowRunner, follows the same rule as one you implement. The release check does not tell them apart, so the rule does not. - A contract test only measures stated behavior. When you upgrade, a new
test in
Tracon.Testing.Contracts.Xunitruns against your store, provider, or judge, and it can fail. Tracon adds one only when the XML documentation or this site stated the behavior before the version that adds the test. The release notes name each new test asClass.Method. If a new test fails against your implementation, either the implementation or the documentation is wrong. Report it as an issue.
What 1.x promises for HTTP, telemetry, configuration, error codes and the CLI
Section titled “What 1.x promises for HTTP, telemetry, configuration, error codes and the CLI”Your application depends on more than the .NET API. A client calls the HTTP
endpoints and reads the SSE event names. A dashboard reads metric and attribute
names. A deployment file holds configuration keys. Your code matches error
codes. A CI script calls the tracon CLI. From 1.0.0-rc.1 each of these
surfaces has the same rule as the .NET API: a change belongs to one SemVer class,
and the release process rejects a release that puts it in the wrong one.
| Surface | A minor release may | Only a major release may |
|---|---|---|
| HTTP | Add an endpoint. Add a field to a response. Add an optional field or parameter to a request. Add a value to a response enum. | Remove an endpoint or a method. Remove a response field, or change its type. Add a required field or parameter to a request. Make an optional one required. Remove a value from a request or a response enum. Make a field that could be null non-null in a request, or one that could not be null nullable in a response. Change a 2xx status code. Tighten the role an endpoint needs. |
| SSE | Add an event name. Add a field to an event payload. | Remove or rename an event name. Remove a payload field. |
| Telemetry | Add a source, an instrument or an attribute. Add an attribute that is off by default to an instrument. | Change the name, the unit or the kind of an instrument. Remove an attribute. Turn an attribute on or off by default. |
| Configuration | Add a key with a documented default. Rename a key if Tracon still reads the old name. | Remove a key. Rename a key and stop reading the old name. Change a default so that behavior changes. |
| Error code | Add a code. | Remove a code, rename it, or change its meaning. This covers the codes of a failed run, a failed job and an OpenAI-compatible error, and the codes of the findings that validating an agent definition returns. |
| CLI | Add a command, an option or an exit code. | Remove a command or an option. Change what an exit code means. |
When a minor release gives a configuration key a new name, Tracon reads the old name for the rest of the 1.x line and logs one warning. The old name is gone only in a major release.
Three more rules complete the table:
- Your code handles a value it does not know. A response enum value, an SSE
event name and an error code can all be new in a minor release. A
switchover them has adefaultbranch. In the TypeScript client, this applies to theswitchover an event name too. - The release process cannot see a role change. A role that an endpoint needs is not in the OpenAPI document. The rule above is written down, and the maintainer reviews it.
- Text for people is not a contract. The
detailof a problem response, a log message and the human output of a CLI command can change in any release. The fields a program reads are the contract: theerrorTypecode, the event name, the key, the option.
Match an error code with a constant. TraconErrorTypes holds the code of a failed
run, of a failed job and of an OpenAI-compatible error as constants, for example
TraconErrorTypes.ToolTimeout. The ErrorType of a Tracon exception and the
errorType that the HTTP API returns carry the same value.
How the release process holds each row:
- Every surface has a file in the repository. One file lists the SSE event names, one the telemetry names with the kind, unit and default attributes of each instrument, one the configuration keys, one the error codes of runs, jobs and OpenAI-compatible errors, one the codes of validation findings, and one the CLI commands and options. A test keeps each file true to the code. The HTTP surface is the OpenAPI document of the build.
- The release process compares each file with the one at the last published version. A line that is gone or changed is a break. A new line is an addition. For HTTP it reads the OpenAPI document with the rules of the table.
- A change that the rules do not name is a break. If the check cannot say which row a change belongs to, it stops the release. It never lets such a change pass. If it cannot read the file of the last published version, it stops too.
- A frozen release rejects a break. When the last published version is
1.0.0-rc.1or later and the new version has the same major version, a break on any of these surfaces stops the release. The release notes do not change that. Before1.0.0-rc.1, and in a new major version, a break passes when the release notes name it in a code span. - A patch release does not add to a surface. A new endpoint, field, event name, key, code or option stops a patch release.
- The files hold names, not meaning. The release process does not see a field removed from an SSE event payload, a configuration default that changed, an exit code that now means something else, an error code that is used for another failure, or a role that an endpoint now needs. The rules above hold for them as well. The maintainer reviews them.
The telemetry row includes the default of an attribute. The tracon.tenant.id
attribute is on spans and on the quota gauges, and it is off by default on the
other metrics. Set Tracon:Observability:IncludeTenantTag to true to add it.
Turning the default back on in a later release is a change of this row.
Package identity
Section titled “Package identity”For packages produced by the official release process, a <package id, version>
pair names exactly one artifact. That guarantee comes from the pipeline, not from
NuGet: a locally packed or otherwise unofficial build can reuse a version string
that already named different content, and NuGet’s cache will not notice — see
the caching caution if you pack previews
yourself. For official artifacts the release process enforces this before a
package is ever produced:
- Every packed artifact traces back to a commit. The build refuses to
produce a package from an uncommitted working tree — there is no version
that can mean “whatever the source happened to be at the time.” Each
package’s
.nuspeccarries the exact commit it was built from. - A version is never silently replaced with different content. If a
release run would produce a
<package id, version>pair that already exists with different bytes, the run stops and the existing, previously published artifact is left untouched — it is never overwritten in place.
This is independent of NuGet’s own package integrity check: every .nupkg
carries a content hash (<id>.<version>.nupkg.sha512 next to it in your local
package cache — find the cache path with dotnet nuget locals global-packages --list), and nuget.org publishes the same hash for the version it lists. If
those two ever disagree, something between the registry and your machine
changed the bytes — that check exists independently of anything Tracon
does, and applies to any NuGet package, not only this family.
Which version do these docs describe?
Section titled “Which version do these docs describe?”This site is built from the repository’s main branch. The .NET reference is generated
from the assemblies built from that same source, and the HTTP reference is generated from
the OpenAPI snapshot in that source tree.
That makes the site the best description of the next build. It can also document a public API that is newer than the preview package you installed. When exact reproducibility matters, pin every Tracon package and check the Release notes entry for the version you installed before you rely on anything this site describes.
Install the newest preview
Section titled “Install the newest preview”Use NuGet’s pre-release selection explicitly:
dotnet add package Tracon --prereleaseThe project template resolves pre-release packages by default, but pinning it makes a team build reproducible:
TRACON_VERSION=1.0.0-preview.N # replace N with the published previewdotnet new install "Tracon.Templates@$TRACON_VERSION"dotnet new tracon-api --TraconVersion "$TRACON_VERSION"Pin the whole package family
Section titled “Pin the whole package family”Do not mix Tracon preview versions. The packages share public contracts, DI registrations, database migrations, and generated code, and one package can call a sibling member that another release removed.
Every Tracon package depends on its Tracon siblings at exactly its own version
([1.0.0-preview.N]), so NuGet and the host stop a mixed graph at three points:
flowchart TD
accTitle: Where a mixed Tracon graph stops
accDescr: Two Tracon packages on different versions fail restore with NU1107. A direct reference to a shared Tracon package overrides the exact range, and NuGet only warns NU1608, unless the project treats NU1608 as an error. A graph that restores anyway, or that uses a package published before the exact range, stops when the host starts.
G[Your project] --> Q{How does the shared<br/>Tracon package enter?}
Q -- through two packages<br/>on different versions --> R1[Restore fails: NU1107]
Q -- through a direct reference<br/>on another version --> R2[Restore warns: NU1608]
R2 -- NU1608 in WarningsAsErrors --> R3[Restore fails]
R2 -- warning only --> S[Host start]
OLD[A package published<br/>before the exact range] --> S
S -- more than one version --> X[TraconException:<br/>the host does not start]
S -- one version --> OK[Normal start]
- Two packages on different versions that share a sibling (for example
Tracon.AspNetCoreandTracon.Voice, which both needTracon.Core) fail restore withNU1107. - A direct reference wins. Referencing
Tracon.Coreat another version overrides the exact range; NuGet reports only warningNU1608. Add<WarningsAsErrors>$(WarningsAsErrors);NU1608</WarningsAsErrors>to stop restore instead. Thedotnet new tracon-apiproject already carries that line. It also turns the same warning from any other package into an error; delete it if you wantNU1608to stay a warning. - A graph that restores anyway does not start. When the host starts, before
any hosted service runs, Tracon compares the versions of the Tracon package
assemblies the process loaded. If they differ, the host stops with a
TraconExceptionthat lists each assembly and its version on its own line.Tracon.Clientis not compared: it talks to a server over HTTP and may call another release by design. The check has no setting to turn it off, and it runs only in a process that starts a host. 1.0.0-preview.1and1.0.0-preview.2accept any newer sibling. They were published before the exact range, so restore cannot stop them; the host check does when a host starts.- A store author who tests with
Tracon.Testing.Contracts.XunitseesNU1608whenTracon.Abstractionsis on a newer version than the contract package. Upgrade the contract package with it: an older contract package can call members the newer abstractions package no longer exposes.
With Central Package Management, keep the versions in one place:
<ItemGroup> <PackageVersion Include="Tracon" Version="1.0.0-preview.N" /> <PackageVersion Include="Tracon.PostgreSql" Version="1.0.0-preview.N" /> <PackageVersion Include="Tracon.OpenAI" Version="1.0.0-preview.N" /> <PackageVersion Include="Tracon.UI" Version="1.0.0-preview.N" /></ItemGroup>If you reference individual packages directly, pin each one to the same version. Avoid floating ranges in production.
The typed client and the server it calls
Section titled “The typed client and the server it calls”Tracon.Client is generated from the exact same OpenAPI document the server
build carries — both come from the same repository build, so they cannot drift
apart at a given version the way a hand-written client could. A caller on a
newer preview than the server it targets sees only the operations the server
actually serves; calling one the server does not yet have returns a 404.
Tracon.Cli follows the same version family, since it wraps Tracon.Client.
The npm package @tracon/client is cut from the same v* git tag as every
NuGet package above — there is no separate npm version scheme. @tracon/client 1.0.0-preview.N and Tracon.Client 1.0.0-preview.N always describe the
identical OpenAPI document.
Persisted session and checkpoint state
Section titled “Persisted session and checkpoint state”An upgrade can leave sessions and workflow checkpoints in storage from before the upgrade. This is the compatibility promise for that stored payload, split by who owns each layer:
| Layer | Owner | Promise |
|---|---|---|
| Record envelope (id, tenant, timestamps, generation, schema version) | Tracon | A minor version only adds envelope fields; it never removes one. An envelope written by an older Tracon version is still readable |
Session state body (SessionRecord.State) |
Microsoft Agent Framework | No promise. A Microsoft Agent Framework minor version bump can make an older body unreadable |
Checkpoint state body (WorkflowCheckpointRecord.State) |
Microsoft Agent Framework | Same as the session body — no promise |
SessionRecord.StateSchemaVersion (always stamped, never null) and
WorkflowCheckpointRecord.StateSchemaVersion (null on a row written before
this field existed) record Tracon’s own envelope generation.
StateMafVersion on both records (null on an older row) records the
Microsoft Agent Framework package version that wrote the body — this is what
lets a failure message name the exact recorded and running versions instead
of guessing.
What happens when a body cannot be read:
flowchart LR
accTitle: Persisted payload restore decision
accDescr: Restoring a session or checkpoint checks the recorded schema generation first, then attempts to deserialize the Microsoft Agent Framework body; either failure produces a defined error naming the recorded and current versions, and the row is never deleted or reset.
A[Restore a session<br/>or checkpoint] --> B{Recorded schema<br/>generation}
B -- newer than<br/>this build understands --> C[Defined error:<br/>recorded vs. current generation]
B -- understood --> D[Attempt to deserialize<br/>the Microsoft Agent<br/>Framework body]
D -- succeeds --> E[Restored normally]
D -- fails --> F[Defined error:<br/>recorded vs. current<br/>Microsoft Agent Framework version]
C --> G[Row is NOT deleted<br/>or silently reset]
F --> G
- The error names both compared facts: the recorded generation or Microsoft Agent Framework version, and the one this build runs. It never says a row “may have become unreadable” without saying why.
- The row is never deleted or silently reset. A silently reset session loses conversation history with nothing telling the caller it happened.
- You have two ways forward: open a new session or workflow run under a new identity, or clear old sessions and checkpoints before the upgrade if you do not need them to survive it.
The supported upgrade window
Section titled “The supported upgrade window”Until now this page said what happens when a stored body cannot be read, but not which upgrades are supposed to work in the first place. This is that promise:
Any Tracon version can read the envelope written by any earlier version
in the same major version line. You are never required to step through
intermediate releases. Going from 1.0.0-preview.3 straight to
1.0.0-preview.19 is supported; so is any 1.x to any later 1.x.
A change that would break this is, by definition, a major version bump — the
envelope generation (StateSchemaVersion) advances, and a build that meets a
generation newer than it understands refuses with a defined error rather than
guessing.
What the promise rests on: the repository keeps session and checkpoint state captured from real runs of earlier versions and reads it back with today’s code on every build. That is a test, not an intention — when it goes red, a release is blocked rather than shipped with a footnote.
Check before you upgrade, not after
Section titled “Check before you upgrade, not after”tracon state-check asks the question while the old build is still
serving traffic. It reads the database directly, so it needs no running
application:
tracon state-check --provider postgres --connection "$TRACON_CONNECTION"Run it with the new version of the tool against a copy of production data. It writes nothing — no row, no migration table entry, no lock — so it is also safe against the live database.
It reports two different things, and reads them out separately:
- A count of every row, grouped by the envelope generation stamped on it, across every tenant. Each generation is marked readable or not by the build running the command. This part is complete.
- A decode of a sample, at most
--samplerows of each generation (default 5), deserialized through Microsoft Agent Framework. This part is a sample. A clean run says the rows that were read came back readable — it never says all of them would.
Exit code 0 means nothing was found that blocks reading; 3 means it found
state this build cannot read. Two kinds of row are reported as checked for
structure only and are never counted as failures: workflow checkpoints (whose
payload has no decoder outside a running workflow) and sessions encrypted at
rest (the CLI holds no content protection key). See the
CLI guide for the full command surface, and Production
deployment for what to do when it comes back red.
Upgrade safely
Section titled “Upgrade safely”- Create a branch and update all Tracon packages together.
- Read the Release notes for public API, configuration, and migration changes — and whether the Microsoft Agent Framework version moved, which affects persisted session and checkpoint bodies (above).
- Build with warnings as errors and run the full test suite.
- Run
tracon state-checkwith the new tool version against a copy of production data (above). A3here is a stop sign, not a warning. - Start a disposable environment against a copy of production-shaped data.
- Inspect
/api/meta, health checks, provider health, and migration diagnostics. - Exercise one synchronous run, one streamed run, every enabled background service, and your approval and guard paths.
- Back up the database before the production migration. Deploy API and worker processes from the same artifact.
- Watch run failures, provider latency, queue depth, webhook delivery, and cost after the rollout.
Database migrations are forward-only. Do not assume that rolling back the application also rolls back the schema. See Production deployment for the migration and backup contract.
Record the version in incident reports
Section titled “Record the version in incident reports”Include these facts when you report a defect:
- the exact Tracon package versions from
dotnet list package; - the .NET target framework and deployment runtime;
- the model provider, model or Azure deployment name, and provider SDK version;
- the storage engine and migration state;
- the failing endpoint or .NET API and a minimal reproduction;
- redacted diagnostics, logs, trace ids, and run ids.
Never attach credentials, connection strings, raw API keys, or unreviewed prompt and tool content.
Read next
Section titled “Read next”- Compatibility matrices — the framework, runtime, and protocol versions each release supports
- Choosing packages — which packages you actually take a version of
- Configuration — the options an upgrade can move