{
  "uri": "https://rsaxb.com/a2a/learnables/v1",
  "name": "Learnables",
  "version": "1",
  "status": "draft",
  "published": "2026-08-17",
  "protocol": "A2A",
  "description": "Lets an agent publish what it can be taught, attach a teachable proposal to a question it asks, and have a human answer absorbed as a new immutable version of its knowledge — without a redeploy and without mutating a definition a running task is pinned to.",
  "categories": [
    "data-only",
    "profile",
    "method"
  ],
  "required": false,
  "specification": "https://rsaxb.com/a2a/learnables/v1",
  "specificationMarkdown": "https://rsaxb.com/a2a/learnables/v1.md",
  "publisher": {
    "name": "RSA Cross Border",
    "url": "https://www.rsaxb.com/"
  },
  "license": "CC-BY-4.0",
  "note": "Independent extension. Not published by, endorsed by, or affiliated with the A2A project.",
  "activation": {
    "header": "A2A-Extensions",
    "value": "https://rsaxb.com/a2a/learnables/v1",
    "dataOnly": "The declaration in capabilities.extensions[].params may be read without activation.",
    "profile": "The teach block and the show-back operation require activation, and the agent must echo the URI in the response header."
  },
  "declaration": {
    "location": "capabilities.extensions[]",
    "params": {
      "type": "object",
      "required": [
        "learnables"
      ],
      "properties": {
        "learnables": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/LearnableDescriptor"
          }
        },
        "teachMethod": {
          "type": "string",
          "description": "Only for the self-owning-agent profile: the RPC method that accepts a Lesson.",
          "examples": [
            "rsaxb.learnables.Teach"
          ]
        }
      }
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://rsaxb.com/a2a/learnables/v1/extension.json",
  "$defs": {
    "LearnableDescriptor": {
      "type": "object",
      "required": [
        "collection",
        "entry",
        "teaches",
        "how",
        "decidedBy",
        "lessonFields"
      ],
      "properties": {
        "collection": {
          "type": "string",
          "description": "The collection's name in the agent's knowledge."
        },
        "entry": {
          "type": "string",
          "description": "Singular noun for one member, for rendering."
        },
        "skills": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Skill ids this learnable affects. Absent means all of them."
        },
        "teaches": {
          "type": "string",
          "description": "What a person is deciding, in their words."
        },
        "how": {
          "type": "string",
          "minLength": 1,
          "description": "How the agent decides today, in prose. MUST NOT be a placeholder."
        },
        "decidedBy": {
          "type": "string",
          "examples": [
            "rules",
            "model",
            "hybrid"
          ]
        },
        "lessonFields": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/LessonField"
          }
        }
      }
    },
    "LessonField": {
      "type": "object",
      "required": [
        "name",
        "label",
        "kind"
      ],
      "properties": {
        "name": {
          "type": "string",
          "description": "Key this field occupies in a lesson value."
        },
        "label": {
          "type": "string",
          "minLength": 1,
          "description": "Human label rendered above the input."
        },
        "kind": {
          "type": "string",
          "description": "Open string, not an enumeration. This version defines \"text\" and \"choice\". An unrecognised kind MUST be rendered as \"text\".",
          "examples": [
            "text",
            "choice"
          ]
        },
        "choices": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Permitted values. Required when kind is \"choice\"."
        },
        "default": {
          "type": "string"
        },
        "help": {
          "type": "string"
        }
      }
    },
    "TeachBlock": {
      "type": "object",
      "required": [
        "collection",
        "entries"
      ],
      "description": "Carried in a question Message's metadata, keyed by the extension URI, under \"teach\".",
      "properties": {
        "collection": {
          "type": "string"
        },
        "entries": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "suggested": {
          "type": "object",
          "description": "Prefill for the lesson value. Its keys MUST be a subset of the applicable lessonFields names, and its scope MUST NOT exceed the evidence it was drawn from.",
          "additionalProperties": true
        },
        "suggestionLabel": {
          "type": "string"
        },
        "lessonFields": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/LessonField"
          }
        }
      }
    },
    "Lesson": {
      "type": "object",
      "required": [
        "collection",
        "entry",
        "value",
        "taughtBy"
      ],
      "properties": {
        "collection": {
          "type": "string"
        },
        "entry": {
          "type": "string"
        },
        "value": {
          "type": "object",
          "description": "Opaque to every party except the learnable being taught. No transport, authority or client may read a named key out of it.",
          "additionalProperties": true
        },
        "taughtBy": {
          "type": "string",
          "description": "Identifies the human. MUST NOT be a service account standing in for one."
        },
        "reason": {
          "type": "string"
        }
      }
    },
    "LessonResult": {
      "type": "object",
      "required": [
        "learned",
        "describes",
        "definitionVersion"
      ],
      "properties": {
        "learned": {
          "type": "boolean",
          "description": "Whether anything changed. False is a normal outcome, not an error."
        },
        "describes": {
          "type": "string",
          "description": "What was learned, phrased by the learnable rather than composed from field names."
        },
        "definitionVersion": {
          "type": "integer"
        },
        "versionId": {
          "type": "string"
        },
        "previousVersionId": {
          "type": "string"
        }
      }
    }
  }
}