# A2A Learnables Extension, Version 1

**Extension URI:** `https://rsaxb.com/a2a/learnables/v1`

**Status:** Draft. Published 2026-08-17.

**Editors:** RSA Cross Border.

**Independent extension.** Not published by, endorsed by, or affiliated with the
A2A project. It is published under a URI its authors control, which the
[A2A extension governance](https://a2a-protocol.org/latest/topics/extension-and-binding-governance/)
permits without registration. The `a2aproject` URI prefixes are reserved for
artifacts that have been through that project's process; this one has not.

**Feedback:** the reference implementation and the issue tracker are maintained
by RSA Cross Border. Comments are welcome.

Paragraphs marked *Rationale* are non-normative and may be skipped.

---

## 1. Abstract

A2A lets an agent say what it can do, and lets it stop and ask a human. It does
not let an agent say **what it can be taught**, and it does not say what becomes
of the human's answer once the task that prompted it ends. Today that answer is
spent once: a person identifies a sender, the task completes, and the next
message from that sender asks the same question.

This extension defines:

1. how an agent **declares its learnable surface** on its Agent Card — what it
   recognises, how it decides today, and what shape an answer must take;
2. how an agent **attaches a teachable proposal** to a question, so a client can
   offer "remember this" without knowing the agent's internals;
3. the **semantics of absorbing a lesson** — refusal, idempotence, versioning,
   and the rule that a lesson never mutates a definition a running task is
   pinned to;
4. a **show-back** operation, so a person sees what the agent now makes of the
   same input instead of the word "saved".

It does **not** define who stores the agent's knowledge, or over what transport a
lesson is written. In many deployments that party is not the agent.

## 2. Status of this document

This is a Draft. Field names and semantics MAY change.

A stable release of this URI is announced by setting `status` to `stable` in the
extension descriptor (Appendix A). Breaking changes are published under a new
URI, never by amending this one ([§15](#15-versioning)).

## 3. Conformance

The key words **MUST**, **MUST NOT**, **REQUIRED**, **SHALL**, **SHALL NOT**,
**SHOULD**, **SHOULD NOT**, **RECOMMENDED**, **MAY**, and **OPTIONAL** are to be
interpreted as described in BCP 14
([RFC 2119](https://www.rfc-editor.org/rfc/rfc2119),
[RFC 8174](https://www.rfc-editor.org/rfc/rfc8174)) when, and only when, they
appear in all capitals.

Three roles carry requirements:

- a **conformant agent** publishes a declaration under this extension's URI;
- a **conformant client** reads that declaration and renders questions from it;
- a **conformant authority** absorbs lessons into the agent's knowledge.

One implementation MAY fill more than one role.

## 4. Motivation

A2A specifies the moment an agent cannot decide: the task moves to
`input-required`, a human answers, the task resumes. It does not specify the
moment after. The answer was evidence about the world, and there is nowhere to
put it. Implementations resolve that in one of three ways:

1. **Discard it.** The same question is asked again tomorrow.
2. **Write it into a prompt or config, then redeploy.** The knowledge reaches
   production days after the person who held it answered.
3. **Let the agent self-modify.** Fast and unauditable: nobody can say what the
   agent knew when it decided, and nothing can be undone.

This extension describes a fourth: the agent publishes what it can be taught, the
client holding the human decides what is written, and the write produces a new
immutable version carrying an author and a reason.

**The agent proposes, the client decides, the authority records.**

## 5. Terminology

**Learnable** — something in an agent's knowledge that a human's answer may
extend. It owns its own vocabulary and its own idea of a valid answer.

**Collection** — the named set a learnable belongs to, e.g. `customers`.

**Entry** — one member of a collection, e.g. `northgate`. A lesson is written
into an entry.

**Lesson** — one human-supplied value addressed to one entry, with an author.

**Lesson field** — one input a client must collect to build a usable lesson
value. The agent describes these; the client renders them.

**Definition** — the versioned, addressable unit of agent knowledge a client
resolves before starting a task. Its internal structure is out of scope.

**Authority** — the party holding definitions and writing lessons into them. MAY
be the agent; in the reference deployment it is a separate control plane.

**Show-back** — read-only re-evaluation of an input under the current
definition.

## 6. Extension declaration

### 6.1 The AgentExtension entry

A conformant agent MUST declare the extension in `capabilities.extensions` with
`uri` set to this document's extension URI, and `required` set to `false`.

*Rationale.* Nothing here changes the meaning of a core A2A request, so refusing
clients that do not understand it would refuse them for no reason.

The declaration is carried in `params`:

```json
{
  "capabilities": {
    "extensions": [
      {
        "uri": "https://rsaxb.com/a2a/learnables/v1",
        "description": "Publishes what this agent can be taught: which customer a message belongs to, and what kind of message it is.",
        "required": false,
        "params": {
          "learnables": [
            {
              "collection": "customers",
              "entry": "customer",
              "skills": ["triage_inbound", "recheck_message"],
              "teaches": "which customer a message belongs to",
              "how": "Each customer carries marks - text that gives them away. Every mark that matches scores; the highest score wins if it clears the identification margin. Nothing matches, nothing is claimed.",
              "decidedBy": "rules",
              "lessonFields": [
                {
                  "name": "pattern",
                  "label": "Text that gives it away",
                  "kind": "text",
                  "help": "An address, a reference, a phrase. Matched without regard to case; regular expressions work if you want one."
                },
                {
                  "name": "where",
                  "label": "Where to look for it",
                  "kind": "choice",
                  "choices": ["from", "subject", "body", "attachments", "any"],
                  "default": "from",
                  "help": "Narrower is safer. 'any' matches the whole message."
                }
              ]
            }
          ]
        }
      }
    ]
  }
}
```

`params.learnables` MUST be an array of Learnable Descriptors
([§6.2](#62-the-learnable-descriptor-object)). It MAY be empty, which asserts
that the agent understands the extension and currently has nothing to teach.

### 6.2 The Learnable Descriptor object

| Field | Type | Required | Meaning |
|---|---|---|---|
| `collection` | string | yes | The collection's name in the agent's knowledge. MUST be unique within one declaration. |
| `entry` | string | yes | Singular noun for one member, for rendering. `"customer"`. |
| `skills` | string[] | no | Skill ids this learnable affects. Absent means all of them. |
| `teaches` | string | yes | What a person is deciding, in their words, not the agent's. |
| `how` | string | yes | How the agent decides **today**, in prose. MUST NOT be a placeholder. |
| `decidedBy` | string | yes | `"rules"`, `"model"`, or `"hybrid"`. |
| `lessonFields` | LessonField[] | yes | The shape of a usable answer. MAY be empty only if the collection accepts an empty value. |

*Rationale.* `how` is required because somebody is about to change how software
decides something that matters, and is entitled to know what it does now, from
the thing doing it. `decidedBy` is required because it changes what a client may
honestly promise: under `"rules"` a taught mark takes effect deterministically,
under `"model"` it is one example among many and the effect is statistical.

### 6.3 The LessonField object

| Field | Type | Required | Meaning |
|---|---|---|---|
| `name` | string | yes | Key this field occupies in a lesson value. MUST be unique within one learnable. |
| `label` | string | yes | Human label. MUST be non-empty and comprehensible to somebody who has never read the agent's source. |
| `kind` | string | yes | Input kind. Open string, not an enumeration. This version defines `"text"` and `"choice"`. |
| `choices` | string[] | no | Permitted values. REQUIRED when `kind` is `"choice"`. |
| `default` | string | no | Value to prefill. With `kind: "choice"`, MUST appear in `choices`. |
| `help` | string | no | One or two sentences under the input. |

A client that encounters an unrecognised `kind` **MUST** render the field as
`"text"`. It MUST NOT drop the field and MUST NOT fail.

*Rationale.* This is the load-bearing rule of the extension. A client rendering
blind from `lessonFields` needs no change when an agent that reads spreadsheets
asks to be taught a column instead of a pattern; a client that hard-codes one
agent's fields must be edited and released. A dropped field, meanwhile, produces
a lesson the agent will refuse at the moment somebody is trying to fix something.

## 7. Activation

The declaration in [§6](#6-extension-declaration) is **data-only**. A client MAY
read it without activating anything, and an agent MUST publish it whether or not
any client activates.

The teach block ([§8](#8-the-teach-block)) and show-back
([§11](#11-show-back)) are **profile** behaviour. A client MUST request them by
including the extension URI in the `A2A-Extensions` request header, and a
conformant agent MUST echo activated URIs in the response header.

```http
A2A-Extensions: https://rsaxb.com/a2a/learnables/v1
```

An agent MUST NOT emit a teach block to a client that has not activated the
extension.

Activation is not authorization; see [§13.2](#132-authorization).

## 8. The teach block

When an agent moves a task to `input-required` because it could not decide
something a learnable covers, it MAY attach a teach block to the question,
carried in the Message's `metadata` and keyed by this extension's URI:

```json
{
  "role": "agent",
  "parts": [{ "text": "I can't tell whose shipment this is. Who should it go to?" }],
  "metadata": {
    "https://rsaxb.com/a2a/learnables/v1": {
      "teach": {
        "collection": "customers",
        "entries": ["northgate", "alhamra", "gulftrade"],
        "suggested": { "pattern": "billing@origin.example", "where": "from" },
        "suggestionLabel": "the address this message came from",
        "lessonFields": [ "...as declared on the card..." ]
      }
    }
  }
}
```

| Field | Type | Required | Meaning |
|---|---|---|---|
| `collection` | string | yes | MUST name a collection declared on the card. |
| `entries` | string[] | yes | Entries a lesson could be written into. MAY be empty when the client is expected to create one. |
| `suggested` | object | no | A prefill for the lesson value. |
| `suggestionLabel` | string | no | Where the suggestion came from, in a person's words. |
| `lessonFields` | LessonField[] | no | Repeats the card's fields so a client can render without a second fetch. |

Keys of `suggested` **MUST** be a subset of the applicable `lessonFields` names.

A `suggested` value **MUST NOT** be wider in scope than the evidence it was drawn
from.

Emitting a teach block **MUST NOT** change how the agent handles the answer to
the underlying question. A client MAY ignore the block entirely, and the task
MUST proceed identically.

*Rationale.* A suggestion is displayed for confirmation, and most people confirm,
which makes its scope a correctness property rather than a convenience. The
reference implementation shipped a defect here: a reference extractor matched
`PA-2026-0901` as `PA-2026`, so confirming what looked like one shipment's
reference would have taught the directory to claim every reference issued that
year.

## 9. The Lesson object

```json
{
  "collection": "customers",
  "entry": "northgate",
  "value": { "pattern": "billing@origin\\.example", "where": "from" },
  "taughtBy": "dana@warehouse.example",
  "reason": "Northgate's billing desk sends the pre-alerts"
}
```

| Field | Type | Required | Meaning |
|---|---|---|---|
| `collection` | string | yes | MUST name a declared collection. |
| `entry` | string | yes | The entry to write into. |
| `value` | object | yes | Opaque to everything except the learnable. Keys SHOULD be `lessonFields` names. |
| `taughtBy` | string | yes | Identifies the human. MUST NOT be a service account standing in for one. |
| `reason` | string | no | Why, in the person's words. |

Every party between the client and the learnable **MUST** treat `value` as
opaque. No transport, authority, or storage layer may read a named key out of it.

*Rationale.* The moment one of them reads `value.pattern`, adding a learnable
that is not about text — a column mapping, a threshold, a unit of measure —
requires a coordinated release of every component in the chain. The reference
implementation enforces this by construction: its control plane contains no field
named `pattern`, and its regression suite drives a `ColumnMapping` learnable,
whose value has no `pattern` key, through the identical code path.

## 10. Absorption semantics

These requirements constrain the *effect* of a write, not its implementation.

### 10.1 The learnable judges the value

The authority **MUST** delegate validation to the learnable being taught and
**MUST NOT** apply its own idea of a valid value. A refusal **MUST** carry a
human-readable reason authored by the learnable:

> `"billing@origin\\.example("` is not a usable pattern: missing ), unterminated
> subpattern at position 24

and not `400 Bad Request: invalid value`. The learnable compiled the value; it is
the only party that knows why the value failed.

### 10.2 Idempotence

Absorption **MUST** be idempotent. A lesson duplicating knowledge the entry
already holds **MUST** report `learned: false`, **MUST NOT** produce a new
version, and **MUST NOT** be treated as an error.

*Rationale.* Two people answering the same way is the normal case, not a fault.

### 10.3 Versioning and pinning

A lesson that changes anything **MUST** produce a new immutable version of the
definition, and **MUST NOT** modify one in place. Therefore:

- a task running against version *n* **MUST** run against version *n* to
  completion, even if *n+1* is activated mid-flight;
- the new version **MUST** appear in an activation history carrying `taughtBy`
  and `reason`;
- the change **MUST** be undoable by the same mechanism that undoes any other
  activation.

*Rationale.* Without pinning, "the agent learns" and "the agent changes
unpredictably under a running task" describe the same behaviour.

### 10.4 The result

```json
{
  "learned": true,
  "describes": "matches 'billing@origin\\.example' in the from",
  "definitionVersion": 12,
  "versionId": "sha256:9f2c...",
  "previousVersionId": "sha256:41ab..."
}
```

| Field | Type | Required | Meaning |
|---|---|---|---|
| `learned` | boolean | yes | Whether anything changed. |
| `describes` | string | yes | What was learned, phrased **by the learnable**. |
| `definitionVersion` | integer | yes | Monotonic version after the write. |
| `versionId` | string | no | Content-addressed identifier of the new version. |
| `previousVersionId` | string | no | What it replaced. |

`describes` **MUST** be produced by the learnable, not composed by the authority
from field names.

*Rationale.* The authority does not know that `where: "from"` means "on the
from-line", so it can only emit something like `customers.northgate.pattern set`
— which nobody can audit six months later.

## 11. Show-back

A conformant agent **SHOULD** expose a read-only operation that re-evaluates a
previously seen input under the currently active definition.

It **MUST NOT** ask a question, **MUST NOT** propose an action, and **MUST NOT**
be pinned to an earlier version.

The report **MUST** distinguish *settled* from *unsettled*, and when unsettled
**SHOULD** say what it saw:

```json
{
  "customer": {
    "settled": true,
    "winner": "northgate",
    "reads": "Reads as Northgate Motors Ltd, on billing@origin.example",
    "candidates": [
      { "name": "northgate", "label": "Northgate Motors Ltd", "score": 0.333,
        "matched": ["billing@origin\\.example"] },
      { "name": "alhamra", "label": "Al Hamra Trading", "score": 0.0, "matched": [] }
    ]
  }
}
```

An implementation **MUST NOT** report the outcome of a lesson using only the
success of the write.

*Rationale.* The case this exists for is the other one:

```json
{ "customer": { "settled": false, "reads": "Still cannot tell whose this is." } }
```

A rule that is saved, valid, and does not do what its author meant. `learned:
true` is true and useless; the unsettled reading is what lets them fix it in the
next minute rather than the next shipment.

## 12. Writing a lesson: transport

The transport for writing a lesson is **out of scope**. The agent recognises, the
client holds the human, and a third party may hold the definitions; specifying
"POST the lesson to the agent" would exclude that topology. Two profiles are
recognised.

### 12.1 External authority (RECOMMENDED)

The agent declares learnables and proposes teach blocks. The client sends the
lesson to an authority it already talks to. The agent learns of the change by
resolving the active definition on its next task.

An agent in this profile **MUST NOT** treat a lesson as accepted merely because
it proposed it, and **MUST NOT** hold local state that a client's decision not to
teach would leave stale.

### 12.2 Self-owning agent (OPTIONAL)

An agent that owns its definitions MAY expose a method extension, declaring
`teachMethod` in `params`:

```json
{
  "uri": "https://rsaxb.com/a2a/learnables/v1",
  "params": {
    "teachMethod": "rsaxb.learnables.Teach",
    "learnables": ["..."]
  }
}
```

The method takes a Lesson ([§9](#9-the-lesson-object)) and returns a result
([§10.4](#104-the-result)). A client **MUST NOT** call it without having
activated the extension. An agent exposing it **MUST** still satisfy every
requirement in [§10](#10-absorption-semantics), including versioning and
reversibility.

## 13. Security considerations

A lesson is a durable, tenant-wide change to automated decision-making, submitted
through a text box by somebody doing another job.

### 13.1 Over-broad values

The dominant risk is not a malicious lesson but a well-meant one that matches far
more than its author believed: a mark on `invoice`, or a pattern one character
from matching every reference in a year.

Implementations **SHOULD** evaluate a proposed lesson against a corpus before
accepting it and **SHOULD** report the match count to the person.
Implementations **MUST NOT** present a suggestion whose scope exceeds the
evidence it was drawn from ([§8](#8-the-teach-block)).

### 13.2 Authorization

The `A2A-Extensions` header is a negotiation mechanism and carries no authority.
An authority **MUST** authorize the writer independently and **MUST** scope every
lesson to exactly one tenant.

*Rationale.* An unscoped lesson is a cross-tenant leak with extra steps: a mark
taught by customer A, applied to customer B's traffic, silently routes B's
shipments into A's name.

### 13.3 Untrusted pattern compilation

Where a learnable compiles a supplied value into an executable matcher — a
regular expression, a query, a template — the implementation:

- **MUST** validate at absorption time and refuse with a reason, rather than at
  match time inside a running task;
- **SHOULD** bound evaluation time or use a non-backtracking engine. A regular
  expression accepted from a text box is a denial-of-service vector against every
  future message.

### 13.4 Attribution and reversal

Every lesson **MUST** be attributable to an identified human and **MUST** be
reversible. *Which rules were in force when this decision was made, and who put
them there* **MUST** be answerable from stored state, without reconstructing
deploy history.

## 14. Privacy considerations

Lesson values routinely contain personal data: the most useful mark for
identifying a customer is often an individual's work address.

Implementations:

- **MUST** treat a lesson value as carrying the same data classification as the
  content it was drawn from;
- **SHOULD** record `taughtBy` as a stable internal identifier rather than
  embedding personal data in an audit trail with a different retention period;
- **MUST** be able to deactivate and tombstone every version containing a
  personal identifier, where that identifier cannot be removed from a historic
  version.

*Rationale.* Content-addressed immutable versions are excellent for auditability
and hostile to erasure. This document does not resolve that tension; it requires
that an implementation resolve it deliberately.

## 15. Versioning

The extension URI is the version. Any change that would break a client reading
`params` — a removed field, a narrowed type, a changed meaning — **MUST** be
published under a new URI ending in a higher version segment.

The following are **not** breaking and MUST NOT change the URI:

- new optional fields on any object defined here;
- new `kind` values, since [§6.3](#63-the-lessonfield-object) requires unknown
  kinds to degrade to `"text"`;
- new `decidedBy` values.

An agent MAY declare several versions simultaneously during a migration. A client
SHOULD use the highest version it understands.

## 16. Relationship to core A2A

Nothing here changes the meaning of a core A2A message. A client ignoring this
extension sees one extra entry in `capabilities.extensions` and one extra key in
a question's `metadata`, both ignorable by construction — which is why `required`
is fixed at `false`.

Three parts of core A2A are load-bearing and are used as specified, not
redefined:

- **`capabilities.extensions`** — the declaration lives in `params`;
- **`input-required`** — the state in which a teach block is emitted;
- **`metadata`** — the augmentation channel, keyed by URI.

## Appendix A. JSON Schema

The machine-readable descriptor and JSON Schema for the objects above are served
at `https://rsaxb.com/a2a/learnables/v1/extension.json`, whose `$defs` define
`LearnableDescriptor`, `LessonField`, `TeachBlock`, `Lesson`, and `LessonResult`.

## Appendix B. Worked example

A pre-alert application, an email agent, and a control plane: three processes, no
redeploy between the first step and the last.

1. **The application fetches the agent's card** and reads one learnable:
   collection `customers`, two lesson fields.
2. **A message arrives** from `billing@origin.example`. No mark matches. The task
   moves to `input-required`, and the question carries a teach block with
   `suggested: { "pattern": "billing@origin.example", "where": "from" }`.
3. **The application renders the fields blind**: a text box labelled "Text that
   gives it away", prefilled, and a select labelled "Where to look for it",
   defaulted to "from". Neither string appears in the application's source.
4. **Dana answers and leaves the teach box ticked.** The application posts a
   Lesson to the control plane. The agent is not involved.
5. **The control plane hands the value to the learnable**, which validates it,
   absorbs it, and phrases the audit line. A new version is published:

   ```
   v12  taught by dana@warehouse.example
        "northgate learned: matches 'billing@origin\.example' in the from"
        reason: Northgate's billing desk sends the pre-alerts
   ```

6. **The application calls show-back** and displays *Reads as Northgate Motors
   Ltd, on billing@origin.example* — the effect, not the word "Saved".
7. **The next message from that address is never asked about.** The task that
   asked the original question was pinned to v11 and finished on v11. Nothing was
   restarted; nothing was redeployed.

## Appendix C. Changelog

| Version | Date | Change |
|---|---|---|
| v1 draft | 2026-08-17 | Initial publication. |

## References

- [A2A Protocol Specification](https://a2a-protocol.org/latest/specification/)
- [A2A Extensions](https://a2a-protocol.org/latest/topics/extensions/)
- [A2A Extension & Binding Governance](https://a2a-protocol.org/latest/topics/extension-and-binding-governance/)
- [RFC 2119](https://www.rfc-editor.org/rfc/rfc2119) / [RFC 8174](https://www.rfc-editor.org/rfc/rfc8174) — requirement keywords
