---
title: Migration
description: When upgrading the TnsAI framework, this page tells you which versions break the public API and where to find the upgrade steps.
---

# Migration

TnsAI is pre-1.0, so the public API can shift between minor versions. The
current published release is listed on
[Installation](../start/install.md). The framework deliberately **does
not ship long-lived `@Deprecated` shims**. When a replacement lands,
the old surface goes in the same release. That means every upgrade is
potentially a small surgical step rather than a sprawling deprecation cleanup,
but it also means you have to read the right release notes to know what to
change.

## Where the migration steps live

From 0.18 on, the [Changelog](../help/changelog.md) gives every change in one line, and [Migrate to 0.18](0.18.md) holds each breaking change in full with what to change for it. For releases before 0.18, each CHANGELOG entry includes a **Migration** subsection whenever consumers need to do something other than bump the version. The guide for moving from version X to Y is *every* entry strictly between X (exclusive) and Y (inclusive).

→ **[Changelog](../help/changelog.md)** has the full list, newest first.

This page is a roadmap: it points to the entries that contain non-trivial breaking changes so you don't have to read the entire changelog when planning an upgrade.

## 0.17.0: RAG module extraction

This change ships in **0.17.0** (framework
[PR #300](https://github.com/TnsAI-Framework/TnsAI/pull/300)), the release
the [installation guide](../start/install.md) is now pinned to. Add
`dev.tnsai:tnsai-rag`, aligned with the 0.17.0 BOM version. It is a published
artifact as of this release.

When upgrading to 0.17.0:

- Add `dev.tnsai:tnsai-rag` for the bundled RAG providers and strategies,
  including applications using `@Retrieval` or `@ChatKnowledge`. Align its
  version with that release's BOM. Keeping only `tnsai-intelligence` no
  longer supplies those providers. This also applies to programmatic/core-SPI
  consumers that discover the bundled provider without using annotations.
  Merely depending on the core SPI types does not install a provider.
- Keep `tnsai-intelligence` if you also use planning, reasoning, FSM or
  cognitive context features. The Java package `com.tnsai.intelligence.rag`
  stays the same, because this is a Maven artifact boundary change, not an import rename.
- `tnsai-server` now depends on `tnsai-rag` directly. Applications that relied
  on Server to bring cognitive Intelligence features transitively must declare
  `tnsai-intelligence` themselves.
- PDFBox and POI remain optional: applications using those extractors still
  supply their parser dependencies. Moving the module does not bundle them
  transitively. PostgreSQL remains a test dependency of the module, not a
  production JDBC driver supplied to consumers.

0.17.0 has **13 runtime framework modules and 15 child modules**:
`tnsai-bom` and build-time `tnsai-rewrite` are the two non-runtime children.
The previous release, 0.16.4, had 12 runtime / 14 child modules.

The source includes the Maven OpenRewrite recipe
`dev.tnsai.rewrite.UpgradeTnsAI_0_17_0`, which adds `tnsai-rag:0.17.0` when it
finds RAG classes or the `@Retrieval` / `@ChatKnowledge` annotations. It does
not upgrade the BOM or cover all core-SPI-only, runtime-only or
reflection-based use: inspect the
result and the application classpath. Do not expect the recipe from the
published 0.16.4 `tnsai-rewrite` artifact.

Source anchors: [module dependencies](https://github.com/TnsAI-Framework/TnsAI/blob/v0.17.0/tnsai-rag/pom.xml),
[Server dependencies](https://github.com/TnsAI-Framework/TnsAI/blob/v0.17.0/tnsai-server/pom.xml),
[recipe](https://github.com/TnsAI-Framework/TnsAI/blob/v0.17.0/tnsai-rewrite/src/main/resources/META-INF/rewrite/upgrade.yml).

## 0.17.0: the other 14 breaking changes

The RAG extraction above is one of 15 documented breaks in this release,
the most breaking one since the module layout settled. The other 14 are not
narrated here. Each has its own entry, with the exact API and the fix, in the
[`[0.17.0]` CHANGELOG section](https://github.com/TnsAI-Framework/TnsAI/blob/dev/CHANGELOG.md)'s
**Migration** subsection. What to look for, grouped:

- **Planning re-checks preconditions and goals against real state**, not the
  planner's own simulation. A plan that completed under 0.16.4 can now throw
  `PlanningFailureException` with a new `Reason.PRECONDITION_STALE` (a step
  refused mid-plan) or `Reason.GOAL_UNSATISFIED_AFTER_EXECUTION` (a goal the
  plan promised and the bodies didn't keep). Both new enum constants break
  an exhaustive `switch` without a `default` branch.
- **Condition and postcondition evaluation changed in four ways**: an enum
  compares by its constant name instead of `toString()`, a `float` compares
  at `float` precision, a quoted literal means a string rather than "any
  type," and (the one most likely to surface silently) **a variable the
  state does not hold now fails every comparison over it, `!=` and negation
  included**, where 0.16.4 read it all as true. A negated precondition over a
  field of any role but a multi-role agent's first, such as `!busy`, can
  start failing for exactly this reason.
- **Access control now runs on every dispatch path**, including SCOP
  Object-target dispatch (0.16.4 skipped it there) and reads the caller from
  the active `InvocationContext` rather than the dispatch context map. See
  the [execution policy guide](../security/execution-policy.md) and the
  updated [Enforcement](../security/enforcement.md) page. **One thing that
  guide is explicit about and this release does not fix: a `@Security`
  placed only on a composed annotation is not detected on *any* dispatch
  path** (`ActionExecutor`, plans and message callbacks included), so
  declare `@Security` directly. A known, open gap, not something 0.17.0
  closes.
- **A plan or message callback whose action declares `@ExecutionPolicy` or
  `@Security` directly is now refused** rather than silently running
  ungated, since neither path went through the access check before. This
  covers only the **bundled** planner (`PlanExecutor`, the bundled
  `PlannerHandle.execute()`). A custom `PlannerHandle` is not checked on
  its behalf and must refuse its own protected steps.
- **`RetrievalConfig` gains a 22nd record component** (`directContextTokens`):
  a pattern that deconstructs the 21 fields of 0.16.4 stops compiling.
- **A role now inherits its superclass's `@ActionSpec` actions and
  `@RoleSpec`.**
- **Conversation content logs under its own namespace**, `com.tnsai.diagnostics.content.*`, separate from operational logs.
- **`FilesystemLiabilitySink` and its default wiring in `tnsai-server` are removed.**
- **Planning's exposed state maps hold an enum's `name()` instead of `toString()`.** `PlanExecutor.extractBeliefs()`, `BackwardChainingPlanner.extractState(Object)` and `PlannerHandle.PlanResult.finalState` used to render an overridden `toString()`. A consumer reading or logging those maps now sees the constant name instead. Signatures are unchanged, so the API-compatibility check does not catch this one.
- **A stale planned step is refused rather than silently skipped when a custom `Planner` declares no goals**: an empty goal list used to make every stale step's skip condition vacuously true. Only affects a custom `Planner`, since neither built-in planner is exposed to it.

## Releases that require active migration

Only release entries where ignoring the steps would actually break consumer code are listed here. Patch releases that touch internals only are omitted.

### 0.18.6: one chat send call, and the principal moves to the invocation

Not additive: some changes fail to compile. Run the `dev.tnsai.rewrite.UpgradeTnsAI_0_18_6` recipe first, then work through [Migrate to 0.18 → 0.18.6](0.18.md#0186).

### 0.18.4: a failed action body tells the model why

Nothing fails to compile; the changes are behavior only. See [Migrate to 0.18 → 0.18.4](0.18.md#0184).

### 0.18.3: plain-object dispatch is wired and checked like a role

Nothing fails to compile; the changes are behavior only. See [Migrate to 0.18 → 0.18.3](0.18.md#0183).

### 0.18.2: artifacts move from Maven Central to repo.tnsai.dev

Add the TnsAI repository to your build before you bump the BOM version. Three further changes affect SCOP run files and `ClassConfig` callers. See [Migrate to 0.18 → 0.18.2](0.18.md#0182).

### 0.18.1: patched dependencies depend on BOM import order

Additive, but its patched dependencies reach your build only if the BOM import order lets them. See [Migrate to 0.18 → 0.18.1](0.18.md#0181).

### 0.18.0: one knowledge annotation, and an action sees only what it names

Run the `dev.tnsai.rewrite.UpgradeTnsAI_0_18_0` recipe first, then work through [Migrate to 0.18 → 0.18.0](0.18.md#0180).

### 0.17.5: Redis stores take a `RedisClient` instead of a `JedisPool`

TnsAI **0.17.5** removes the `JedisPool` constructors of `RedisIdempotencyStore` and `RedisCheckpointStore`. The pool constructors are gone, with no compatibility overloads. Both stores now take a pooled `redis.clients.jedis.RedisClient`, with or without a custom key prefix. The Redis server needs nothing new: the checkpoint lookup uses `ZRANGE -1 -1` and does not require `ZRANGE REV`.

- **Find the call sites first:** run the `dev.tnsai.rewrite.UpgradeTnsAI_0_17_5` recipe from the `tnsai-rewrite` module **before** you bump `tnsai.version`. Your project is still on 0.17.4 at that point, so name the 0.17.5 recipe artifact explicitly:

  ```bash
  mvn -U org.openrewrite.maven:rewrite-maven-plugin:run \
    -Drewrite.recipeArtifactCoordinates=dev.tnsai:tnsai-rewrite:0.17.5 \
    -Drewrite.activeRecipes=dev.tnsai.rewrite.UpgradeTnsAI_0_17_5
  ```

  After the bump the `JedisPool` constructors no longer exist, so the recipe has nothing to match and marks nothing. It marks every `JedisPool` construction of the two stores with a bare `/*~~>*/` and does not rewrite it, because the client configuration cannot be translated mechanically. Remove the markers by hand once each call site is migrated.
- **Manual path:** replace the `JedisPool` you passed in with a `RedisClient`. Keep the same authentication, database, TLS, timeout and pool configuration. The application owns the client and closes it at shutdown, and the stores reuse it and never close it themselves.
- **Raise your own Jedis:** `redis.clients:jedis` is an optional dependency of `tnsai-core` that your build declares, so TnsAI does not upgrade it for you. Set it to **7.2.0 or later**, because `RedisClient` first appears in Jedis 7.2.0. TnsAI 0.17.5 is built and tested only against `8.0.1`. See [`RedisIdempotencyStore`](../tools/idempotency.md#redisidempotencystore) for a sample.
- See [Changelog → 0.17.5](../help/changelog.md#0-17-5-redis-client) for the full entry (auto-synced from the framework CHANGELOG).

### 0.17.5: `BridgeLLMClient` failures report their real type

Nothing fails to compile, but retries on the SCOP HTTP fallback path change. `BridgeLLMClient.chat()` used to report every failure as `ErrorType.UNKNOWN`, which is retryable. It now reports the classified type.

- A `RetryPolicy` keyed on `SERVER_ERROR` or `MODEL_OVERLOADED` now retries 5xx and 429 failures.
- 401/403 and other 4xx failures are no longer retryable. If you relied on them being retried, review your policy before upgrading.
- An empty 2xx body, or a 2xx body carrying an `error` object, stays `UNKNOWN` and retryable, as before. The bridge itself still sends each request once.
- See [Migrate to 0.18 → Bridge retries follow the error type](0.18.md#bridge-retries-follow-the-error-type-0175) for the status-to-type table, and [Changelog → 0.17.5](../help/changelog.md#0-17-5-bridge-retry-types) for the full entry.

### 0.17.5: document extraction refuses oversized or relabelled inputs

Nothing fails to compile, but PDF and OOXML extraction in `tnsai-rag` now refuses inputs past its page, glyph, node and inflation caps instead of loading them. Through ingestion a refused file is an `EXTRACTION` failure, and a direct extractor call throws `IllegalArgumentException`.

- Inputs that used to ingest can now be refused: PDFs past the page or glyph caps, OOXML packages past the entry, node or inflation caps, spreadsheets beyond about 3,100 rows × 50 columns, a legacy `.xls` under an XLSX label and default-password-encrypted XLSX.
- If your corpus holds large spreadsheets or long PDFs, run an ingestion pass on 0.17.5 and check the failures before you roll it out.
- The caps do not bound memory against a crafted PDF: stream decompression size is not checked yet.
- See [Formats → PDF and OOXML caps](../rag/file-formats.md#pdf-and-ooxml-caps) for the full list, and [Changelog → 0.17.5](../help/changelog.md#0-17-5-extraction-caps) for the full entry.

### 0.17.5: SCOP routine logs move to `DEBUG`

Nothing fails to compile, but routine `INFO` records in `SCOPBridge`, `LLMDispatcher` and `LLMClientFactory` now log at `DEBUG`. These include action execution, LLM resolution, client creation and request/response summaries.

- If dashboards or alerts match those lines, they stop firing on 0.17.5.
- `WARN` and `ERROR` records, the HTTP-fallback record and the source-override and external-routing records stay at `INFO`.
- Do not raise `LLMDispatcher` or any logger above it to `DEBUG`: it logs the last four characters of the API key. See [SCOP Bridge → Log levels](../connect/scop.md#log-levels) for the loggers that are safe to raise.

### Maven groupId `io.github.tansuasici` → `dev.tnsai`

Coordinates move to the [tnsai.dev](https://tnsai.dev) namespace. Artifact IDs stay. Java packages (`com.tnsai.*`) stay. Versions already on Maven Central under `io.github.tansuasici` (through **0.15.0**) keep resolving as real artifacts. **`0.15.1` is the handover**: on the old groupId it is a relocation POM, so bumping to it follows to `dev.tnsai` with a Maven warning. Bumping to `0.15.0` instead resolves a real artifact and stays on the retired coordinate.

OpenRewrite recipe IDs `io.github.tansuasici.rewrite.UpgradeTnsAI_*` do **not** change.

- **Automated path:** `mvn rewrite:run` with `dev.tnsai.rewrite.ChangeMavenGroupId` (the `tnsai-rewrite` module).
- **Manual path:** replace `<groupId>io.github.tansuasici</groupId>` (and the Gradle `io.github.tansuasici:` prefix) with `dev.tnsai`.

### 0.16.0: the `KnowledgeBase` chat bridge is removed

`AgentBuilder.knowledgeBase(...)`, `AgentBuilder.knowledgeBaseTopK(...)`, `Agent.setKnowledgeBase`/`getKnowledgeBase`, `Agent.setKnowledgeBaseTopK`/`getKnowledgeBaseTopK`, the matching `AgentOrchestrator` and `AgentChatOrchestrator` members, `ChatKnowledgeBinding.snapshot(...)` and `ChatKnowledgeBinding.SNAPSHOT_SOURCE` are removed. The `KnowledgeBase` type stays. To ground chat on a corpus the application owns, declare a `MEMORY` entry and bind the corpus with `ChatKnowledgeBinding.live(...)`, as [RAG → Application-supplied live sources](../rag/index.md#application-supplied-live-sources) shows.

### 0.14.0: `@Param` deleted

TnsAI **0.14.0** removes `@com.tnsai.annotations.Param`. The annotation shipped in **0.13.0** and never had a runtime reader. `ActionDiscovery.discoverParameters` builds every `ParamSpec` from `Parameter.getName()` under the `-parameters` compiler flag, so an action's LLM-visible name has always been the Java parameter name. A mismatch with `@Param(name = "q") String query` silently resolved to `query`.

`@ToolParam` and `@LLMParam` are different, live annotations and are untouched.

- **Automated path:** `mvn rewrite:run` with `io.github.tansuasici.rewrite.UpgradeTnsAI_0_14_0` (the `tnsai-rewrite` module). It deletes `@Param` usages only.
- **Manual path:** delete every `@Param` usage. Parameter names and types continue to come from the method signature, so nothing else changes. `-parameters` is already set by the parent POM.
- See [Changelog → 0.14.0](../help/changelog.md#0140---2026-08-18) for the full entry (auto-synced from the framework CHANGELOG).

This shipped in **0.14.0**.

### 0.13.0: declarative RAG starts taking effect, and `@KnowledgeSource` narrows to ingestion

The largest breaking release so far (21 entries), and most of it is **behavioural**: `@Retrieval` members that were accepted and then silently discarded are now enforced. Your code still compiles. It just starts doing what the declaration always said.

**Read your `@Retrieval` declarations before upgrading.** `rerank`, `cache`/`cacheTTL`, `onFailure`, `queryExpansion`, `deduplicate`, `contextWindow`/`includeSpec` and the `GRAPH`/`HIERARCHICAL`/`TEMPORAL` strategies were inert, and they now change retrieval behaviour. Two specifics worth knowing:

- `cache` defaults to `true` with a 300s TTL, so caching switches on for every existing `@Retrieval`. Corpus changes are picked up on the next dispatch only if you call `RoleRagBinding.invalidate(Class)`. Otherwise entries clear by TTL or LRU. Set `cache = false` to keep the previous behaviour.
- `rerank`, `queryExpansion` and `strategy = GRAPH` resolve through SPI seams with **no bundled provider**. Enabling them without an add-on module now throws at dispatch instead of being ignored.

**`@KnowledgeSource` is now ingestion-only**: 17 members down to 6 (`name`, `type`, `path`, `connection`, `query`, `enabled`). The 11 removed members (`provider`, `index`, `topK`, `minSimilarity`, `embeddingModel`, `dimensions`, `namespace`, `filter`, `cache`, `cacheTTL`, `priority`) never had a reader, so deleting them changes nothing at runtime. Retrieval tuning belongs to `@Retrieval`, which removes the old ambiguity where both annotations declared `topK`/`cache`/`cacheTTL` with no rule for which wins.

`KnowledgeType` drops to `FILE`, `URL`, `DATABASE`, `MEMORY`, and the default moves from `VECTOR_DB` to `FILE`. `VECTOR_DB`, `WEB_SEARCH` and `CACHE` are removed with **no replacement**: a remote index is queried per request, which the ingest-time `SourceLoader` seam cannot express. Those belong behind `RetrievalEngineProvider`.

- **Automated path:** `mvn rewrite:run` with `io.github.tansuasici.rewrite.UpgradeTnsAI_0_13_0` (the `tnsai-rewrite` module). 73 entries: 61 type moves from the `com.tnsai.quality.*` and `com.tnsai.agents.groups.*` consolidations, 11 attribute removals for the narrowed `@KnowledgeSource`, and one method rename (`RoleRagBinding.evictForTesting` → `invalidate`). Activate the recipe for the version you are moving **to**.
- **What the recipe cannot do:** the behavioural changes above. A recipe could auto-insert `cache = false` and pin you to the old behaviour, which is the opposite of what you want to decide. It also does not migrate the removed `KnowledgeType` values (no target to rewrite to).
- **If you implement `SourceLoader`:** `load(...)` and the optional `metadata(...)` hook now take `com.tnsai.rag.KnowledgeSourceConfig` instead of the `@KnowledgeSource` annotation. `KnowledgeSourceConfig`'s six components are name-for-name and type-for-type identical to the narrowed annotation's six members, so a body that reads `name` / `type` / `path` / `connection` / `query` / `enabled` compiles unchanged and only the parameter type in the signature needs editing. If your loader read one of the 11 removed members (`topK`, `provider`, `embeddingModel` and the rest), that is a separate break to resolve. In practice a loader reads `path` / `connection` / `query`, not retrieval knobs. Not yet covered by the recipe.
- See [Changelog → 0.13.0 → Migration](../help/changelog.md#0130---2026-08-01) for the full entry.

### 0.12.0: name collisions + 23 orphan annotations removed

Two simple-name collisions in core, plus the 0.11.1-era orphan-annotation
and `@LLM` removals bundled into the first release after 0.11.0.

- The `com.tnsai.identity.AgentSpec` **record** is renamed to `AgentDescriptor`. (The `@AgentSpec` *annotation* is a different type and is unchanged.)
- The `@com.tnsai.roles.annotations.RoleIdentity` **annotation** is renamed to `@RoleDeclaration`. (The runtime `com.tnsai.models.role.RoleIdentity` identity class is unchanged.)

- **Combined guide:** [0.11 → 0.12](0.12.md): removed list, newly active wiring, Config records, recipe.
- **Automated path:** `mvn rewrite:run` with `io.github.tansuasici.rewrite.UpgradeTnsAI_0_12_0` (the two renames only).
- See [Changelog → 0.12.0 → Migration](../help/changelog.md#0120---2026-06-04) for the full entry.

### 0.7.0: Legacy `Tool` interface removed

Function-shape `ToolMethod` is now the only tool abstraction in the runtime. If your code still does `class MyTool implements Tool`, this is the breaking change to plan for.

- Migration paths: convert to a POJO with `@Tool`-annotated methods (recommended), or build a `DynamicToolMethod` directly.
- See [Changelog → 0.7.0 → Migration](../help/changelog.md#070---2026-04-29) for the exact replacement snippets.

### 0.6.0: `Tool` interface metadata methods + `ChatRequest.tools` type changed

Removed the 12 metadata-discovery default methods (`getCategory`, `getUsageExamples`, etc.) and changed `ChatRequest.getTools()` from `List<ToolDefinition>` to `List<Map<String, Object>>` (JSON-Schema fragments).

- Custom-tool-catalog callers that built `ChatRequest` directly must switch to the new map shape.
- Direct `Tool` implementers can simply drop overrides of the removed metadata methods, since they're no longer called.
- See [Changelog → 0.6.0 → Migration](../help/changelog.md#060---2026-04-29) for before/after snippets.

### 0.5.7: Legacy tool catalog removed from `tnsai-tools`

The 130+ `extends AbstractTool` classes were replaced by ~60 typed POJOs exposing ~190 `@Tool`-annotated methods. Most consumers already used `AgentBuilder.toolPojos(...)` and don't need to touch anything.

- Consumers still using `AgentBuilder.tool(Tool)` keep working through the compatibility surface in this release.
- See [Changelog → 0.5.7 → Consumer migration](../help/changelog.md#057---2026-04-29).

### 0.5.0: `AgentState.READY` renamed to `RUNNING`

Single-token rename. No deprecation shim: search-and-replace `AgentState.READY` → `AgentState.RUNNING` in your code.

Other 0.5.0 behaviour changes that *can* surface as silent breaks if your code depended on them:

- `Agent.chat()` now throws `IllegalStateException` after the agent has been stopped (was silent / undefined before).
- `BridgeLLMClient.streamChat()` now throws `LLMCapabilityException` (was returning a single-element synthetic stream).
- `BridgeLLMClient.chat()` now throws typed `LLMException` (was raw `RuntimeException`).

See [Changelog → 0.5.0 → Migration notes](../help/changelog.md#050--2026-04-26).

### 0.4.0: Monorepo migration

Not a code break, but a coordinate break: the 11 separately-published modules consolidated under a single `tnsai-bom`. The recommended dependency shape is now to import the BOM once and depend on individual modules without `<version>`.

- See [Changelog → 0.4.0 → For Consumers](../help/changelog.md#040--2026-04-22) for the new dependency snippet.

## Optional refactors

These are not release breaks: the old shape still compiles and runs. They move code to the pattern the current pages teach.

### From `return null;` bodies to `@Capability`

The `@Capability` pattern ships since **0.4.0** ([Changelog → 0.4.0](../help/changelog.md#040--2026-04-22)). A dispatched `@ActionSpec` method (`LLM` / `MCP_TOOL` / `WEB_SERVICE`) with a `return null;` body still works, because `ActionExecutor` never runs that body. But every role repeats the annotation, and a direct call returns `null`. To move such methods onto a capability:

1. For each dispatched `@ActionSpec` method whose body is `return null;`, extract it to a `@Capability` interface.
2. Give the interface method a `default { throw Actions.dispatchedByFramework(); }` body.
3. On the role class, remove the original method entirely and add `implements YourCapability`.
4. Methods that have a meaningful body (typically because they declare an `ActionResult` parameter for post-processing) stay on the role class unchanged.

**Before**

```java
@RoleDeclaration(name = "Editor", goal = "Produce clean articles")
public class EditorRole extends Role {

    @ActionSpec(type = ActionType.LLM, description = "Summarise the text",
                llmSystemPrompt = "You are concise.", llmTemperature = 0.2f)
    public String summarize(String text) {
        return null;
    }

    @ActionSpec(type = ActionType.LLM, description = "Translate to the target language")
    public String translate(String text, String targetLanguage) {
        return null;
    }
}
```

**After**

```java
@Capability
public interface Summarizer {
    @ActionSpec(type = ActionType.LLM, description = "Summarise the text",
                llmSystemPrompt = "You are concise.", llmTemperature = 0.2f)
    default String summarize(String text) {
        throw Actions.dispatchedByFramework();
    }
}

@Capability
public interface Translator {
    @ActionSpec(type = ActionType.LLM, description = "Translate to the target language")
    default String translate(String text, String targetLanguage) {
        throw Actions.dispatchedByFramework();
    }
}

@RoleDeclaration(name = "Editor", goal = "Produce clean articles")
public class EditorRole extends Role implements Summarizer, Translator {
    // No capability bodies.
}
```

Composition, override and validation rules: [Capabilities](../agents/capabilities.md).

## When in doubt

If you're skipping multiple versions, walk forward one minor at a time and read the migration subsection of each entry. The deletions are intentionally aggressive: sleeping on the changelog for six months and trying to jump from 0.5 to 0.10 in one go is harder than four 30-minute upgrade sessions spread across releases.

For changes that aren't covered above but caused you grief, [open a discussion on the framework repo](https://github.com/TnsAI-Framework/TnsAI/discussions), and the entry will land here in the next release.
