Concept

Extension action classes

Cortex ships five canonical action classes — communicate, schedule, remind, inform, shield. That set is sufficient for the founder's executive-assistant use case. It is not sufficient for verticals. A finance customer needs transact. A repos customer needs commit. A coding-agent customer needs code. The extension action class protocol lets you register domain-specific classes that participate in the trust state machine and dispatch protocol identically to canonical ones — without internal enum migrations.

The three tools

Namespace convention: {client_namespace}.{action_class}

Every custom class is identified by a namespaced string. The namespace is owned by the registering client_id within the tenant for the tenant's lifetime. Collisions are rejected at registration time with 409 Conflict { code: 'namespace_owned' }.

Tenants are isolated: customer A's acme.transact cannot collide with customer B's acme.transact. Namespace ownership is per-tenant.

Example: register a finance customer's transact class

ts
const { class_id, namespaced_name } = await cortex.tools.call('action_classes.register', {
  namespace: 'acme',
  name: 'transact',
  payload_schema: {
    type: 'object',
    required: ['amount_cents', 'currency', 'to_account_id'],
    properties: {
      amount_cents: { type: 'integer', minimum: 1 },
      currency: { type: 'string', enum: ['USD', 'EUR', 'GBP'] },
      to_account_id: { type: 'string' },
      memo: { type: 'string', maxLength: 280 },
    },
    additionalProperties: false,
  },
  allowed_modes: ['ask', 'notify'],   // no silent execution for financial actions
  display_name: 'Transact',
  description: 'Send funds from a Plaid-linked account to an authorized recipient.',
  legal_effect_classification: 'always',   // every transact action is legally significant
});

// → namespaced_name = "acme.transact"
// → trigger envelope action_class field accepts "acme.transact"
// → register a handler for this class via /v1/clients/{client_id}/action_handlers

What the protocol gives you

  • Trust state machine participation. Custom classes seed at Level 1 baseline; per-counterparty graduation works via the same ceremony as canonical classes (typed “Promote” confirmation, evidence summary, audit row).
  • Dispatch protocol participation. Register a handler with action_class: "acme.transact" via /v1/clients/{client_id}/action_handlers; Cortex dispatches signed envelopes to your endpoint the same way it does for canonical classes.
  • Trigger envelope acceptance. No envelope schema change — ADR-0019 §2's action_class: string already accepts arbitrary strings.
  • Payload validation at dispatch. Your JSON Schema is canonicalized, content-hashed, and validated against every outbound envelope. Malformed payloads are caught before they reach your handler — dispatch failures surface in the operator dashboard.
  • Approval ceremony, your UI. When mode = "ask", your handler renders the approval ceremony in your app's UI using the envelope payload + reasoning + counterparty fields.

Schema validation: JSON Schema 2020-12 subset

The payload_schema is validated at registration as a subset of JSON Schema 2020-12. Allowed keywords: type, properties, required, additionalProperties, items, enum, oneOf, anyOf, allOf, not, const, format (limited set), minLength, maxLength, minimum, maximum, minItems, maxItems, pattern, description, title, examples. Disallowed: $ref, if/then/else, unevaluatedProperties, arbitrary custom formats. Size cap 32 KB; nesting cap 8 levels.

Quota

Per-tenant active class cap applies (see rate limits & quotas). Inherited canonical classes do not count toward your cap. Over-quota: 429 too_many_classes.

Lifecycle: deregistration is a soft-delete

action_classes.deregister sets deregistered_at on the row but preserves all historical action_ledger entries that reference the class. Re-registration of the same namespaced name within the same tenant requires the same client_id that originally registered it — this prevents accidental namespace handoff between clients.

Cross-references

  • Dispatch protocol (ADR-0019) — how extension-class envelopes are signed and delivered.
  • Concept: Counterparty depth — trust pairs for custom classes work identically to canonical ones.
  • ADR-0022 (full protocol spec); Architecture §4a.8 (Extension Action Classes); Pattern §5.15 (Extension Class Pattern).