Skip to content

Cortex — Axonis Decision Intelligence Platform Architecture

What the Axonis Decision Intelligence (ADI) platform IS — its architecture, identity model, objects, surfaces, and configuration system. ADI is a federated AI platform for decision intelligence: AI goes to the data, not data to AI. This spec describes the platform from the Cortex point of view; the object schemas it references are authoritative in component.cortex.decision-evidence, and the pack schemas in component.cortex.pack-reference.

Normative Language

Term Meaning
MUST Absolute requirement. Violation is a defect.
MUST NOT Absolute prohibition. Violation is a defect.
SHOULD Recommended. Deviation requires documented rationale.
MAY Optional. Implementation choice.
OPEN GAP Behavior unspecified or unimplemented. Requires resolution before production.

Decision Operating System

Axonis is a decision operating system: SSO identifies the user, packs configure behavior, UDS governs visibility, Cortex enforces rules, Beacon renders the workflow, and DES preserves the evidence chain from signal to sealed decision.

            AXONIS DECISION OS — AI goes to the data. Humans attest the decision.

   IDENTITY + ACCESS                          CONFIGURATION
   SSO / KEYCLOAK                             PACKS
   users, roles, groups, AUTHORIZATION keys   Profile → capabilities
        │ JWT                                 Domain → models / governed fields
        ▼                                     Experience → UI / vocabulary
   BEACON (UI renders only: Monitor,          Accountability → rules / routing
   Explore, Investigations, Tasks)            Templates / Policies
        │ MCP initialize(profile_id)
        ▼
   CORTEX (loads packs, executes tools, enforces guardrails, binds session/profile)
        │ queries with visibility keys
        ▼
   UDS (sole ABAC authority, federated data access, deny_mode: omit)

Decision Evidence Flow

Signal ──▶ Investigation ── gathers ──▶ Blocks/Evidence (transient → curated/pinned → frozen/hashed)
                │
                ├─ emits append-only Events
                ├─ spawns Tasks (human handoff during deliberation)
                └─ produces Edition (evidence_manifest + narrative_snapshot + content_hash + attestation)
                       └─ Sealed Decision └─ optional Decision Effects (post-attestation execution only)

OODA / User Surfaces

OBSERVE → ORIENT → DECIDE → ACT
Monitor   Explore   Investigations   Tasks

Monitor = what needs attention (signals/KPIs). Explore = gather and shape evidence (query/pin). Investigations = write and seal the decision (edition/review). Tasks = route human work, not workflow orchestration.

Hard Boundaries / Inviolable Invariants

  1. UDS is the only ABAC authority — Cortex and Beacon never filter data.
  2. Packs configure behavior; code must not invent it.
  3. Events are append-only — no UPDATE, no DELETE.
  4. Frozen evidence cannot change — SHA256 digest locked forever.
  5. Editions require frozen evidence — can't attest to moving targets.
  6. AI may assist; only humans attest.
  7. "No action" is still a decision — explicit closure required.
  8. Tasks are deliberation work; Effects are execution work.

Services

Service Port Role
Beacon (MCP Client) 8002 Renders UI, proxies to Cortex. No business logic.
Cortex (MCP Server) 8000 Loads packs, executes MCP tools, enforces guardrails.
REST API 5000 CRUD for objects. Schema validated against the wire schema.
SSO (Keycloak) Identity, roles, groups, visibility key claims.

Communication flow: Angular → Beacon /api/mcp → Cortex /mcp (JSON-RPC); Angular → Beacon /api/cortex/chat → Cortex /chat/stream (SSE); UDS queries carry the user's visibility_keys → ABAC filtering at cell level.

System Authority Matrix

Every concern has exactly ONE authoritative owner. If two documents disagree, the authority listed here wins.

Concern Authority NOT Decided By
User identity, authentication SSO (Keycloak) Beacon, Cortex, Packs
Capabilities (what a user can do) Profile Pack → resolved archetype SSO roles, frontend code
Data visibility (which fields a user sees) UDS ABAC via visibility_keys from JWT Cortex, Beacon, Profile Pack
Decision governance (evidence rules, attestation, review) Accountability Pack Experience Pack, frontend code
UI structure (nav, vocabulary, KPIs, suggestions) Experience Pack Accountability Pack, Cortex
Data models (field names, types, governed fields) Domain Pack Experience Pack, frontend code
Object lifecycles (valid states, transitions) DES lifecycle specs (component.cortex.investigation-lifecycle, component.cortex.signal-lifecycle, component.cortex.task-and-effect) Frontend display states, ad-hoc code
Implementation rules (code patterns) component.cortex.developer-rules Individual developer judgment
AI assistant behavior (drift prevention) SDD skills Claude's training data
Event types and surface boundaries component.cortex.decision-evidence + component.cortex.task-and-effect Frontend component organization
Wire format (API shapes) REST objects.yml Frontend interfaces, Cortex DTOs
Pack schemas and inheritance pack bundle YAML (loaded into ES by the loader) Beacon docs, CLAUDE.md

Identity Terminology

Four concepts developers frequently conflate:

Term What It Is Where It Lives Example
SSO Role An identity claim from the IdP — who the user IS JWT realm_access.roles[] RELATIONSHIP_MANAGER
Profile A platform persona binding a user to capabilities, packs, data access bundle profiles.yaml thebank_rm_v1
Archetype A capability baseline profiles inherit from bundle archetypes.yaml analyst, commander, principal
Capability A specific permission (boolean, resolved from archetype + domain overrides) Resolved at MCP initialize; string[] on frontend edition_manage, edition_attest

The mapping: SSO Role → matched to Profile (via auth.roles_any) → Profile specifies Archetype → Archetype provides base Capabilities → Domain overrides add/remove. SSO roles do NOT determine capabilities directly.

Canonical Domain Model

Terminology

Canonical Term Wire Protocol Name UI Display Aliases (DO NOT USE in new code)
Signal signal Configurable via vocab alert, notification
Investigation insight (wire only) Configurable (default "Investigation") insight, case, analysis, credit review
Block block Configurable (default "Evidence") evidence, card, data point
Event event / insight_event Internal; not user-facing action, log entry, verb
Edition edition / edition_snapshot Configurable via vocab snapshot, decision, sealed record
Task task Configurable (default "Tasks") assignment, work item, inbox item
Decision Effect decision_effect Internal effect, execution, dispatch. NOT YET IMPLEMENTED.
Profile profile Internal persona, user config
Pack varies by type Internal config, bundle. JSON config, never code.
Visibility Key visibility_key Internal marking, read key, ABAC key. UDS-level cell security; NOT a role.
Federate federate Internal data source, index, federation node

Object Graph

Five core objects: Signal, Investigation (wire insight), Block, Event, Edition. One optional extension: Decision Effect (not implemented). Full schemas and identifier formats in component.cortex.decision-evidence#object-model.

Note on identifiers: DES prefixes (blk_, ins_, evt_, edn_, eff_) are the vendor-neutral standard; the Axonis implementation currently uses plain UUIDs in the REST wire format, which is the runtime authority.

Governed Field Convention (_# Suffix)

Fields whose visibility is controlled by UDS ABAC use the _# suffix in wire names, signalling that the field requires a matching visibility_key:

customer_id               ← No suffix → visible to all profiles
customer_name_#           ← _# → requires FIN_PII_KEY
risk_rating_#             ← _# → requires SENSITIVE_RISK_KEY
internal_watchlist_flag_# ← _# → requires WATCHLIST_KEY

Rules: the _# suffix is part of the field name in ES indices, queries, and API responses; UDS applies deny_mode: omit (unauthorized fields silently excluded); domain packs MUST use _# for any field with metadata.sensitivity: governance; Beacon and Cortex MUST NOT strip or add _# suffixes.

Identity and Access

Resolution Chain

IdP (SSO/Keycloak) → JWT access_token (sub, email, roles, groups, AUTHORIZATION keys)
  → Beacon decodes JWT (no signature verify — relies on SSO proxy trust boundary)
  → User selects profile from /api/profiles → Frontend calls MCP initialize(profile_id)
  → Cortex loads profile + domain + experience + accountability packs
  → Cortex stores profile_id in Redis session (keyed by JWT session_id)
  → UDS applies visibility_keys from profile at query time (deny_mode: omit)

Layer Responsibilities

Layer Decides Does NOT Decide
SSO/IdP User identity, realm roles, groups, visibility keys Profile selection, UI rendering
Profile Pack Capabilities, visibility_keys, allowed_models, federate ABAC enforcement, UI rendering
Accountability Pack Decision types, evidence minimums, attestation, review routing UI layout, data queries
Experience Pack Nav config, vocabulary, monitor KPIs, explore suggestions Decision rules, visibility, capabilities
Domain Pack Data models, subject types, vocabulary, signal type configs Authorization, accountability
UDS/ABAC Cell-level data filtering, visibility enforcement Authentication, profile selection
Beacon Rendering, navigation, user interactions Data filtering, workflow rules, capability enforcement
Cortex MCP tool execution, pack loading, guardrail enforcement Authentication, data filtering, UI rendering

JWT Token Claims

Claim Used By Example
sub Session tracking, actor ID "f47ac10b-58cc-..."
session_state / sid X-Session-ID header, Redis key "abc123-session-id"
preferred_username Display, event actor "Riskmgr@axonis.ai"
realm_access.roles[] Role matching in packs ["RELATIONSHIP_MANAGER"]
groups[] Group matching in packs ["/CreditTeam"]
AUTHORIZATION.READ[] UDS visibility (read) ["INTERNAL_KEY \| FIN_PII_KEY"]
AUTHORIZATION.WRITE[] UDS visibility (write) ["INTERNAL_KEY"]

Visibility keys are pipe-delimited within the AUTHORIZATION claim array.

Session Headers

Header Source Purpose
Authorization: Bearer <token> localStorage Authentication
X-Session-ID JWT session_state or sid Redis session key
X-Profile-ID Current selected profile Profile context

Profile is NOT passed in the chat request body. Cortex reads profile_id from the Redis session set during MCP initialize.

The Pack System

Seven Pack Types

# Pack Type Purpose Loaded By
1 Profile Capabilities, visibility, models, federate MCP initialize
2 Domain Data models, subject types, field governance (_#) MCP initialize
3 Experience UI nav, KPIs, vocabulary, explore suggestions MCP initialize
4 Accountability Decision rules, evidence minimums, attestation, signal policies MCP initialize
5 Decision Template Edition structure: evidence, sections, attestation Referenced by accountability
6 Task Template Task structure: type, assignment, SLA, completion Referenced by accountability
7 Signal Policy Signal generation: thresholds, severity, routing Referenced by accountability

Full schemas and inheritance in component.cortex.pack-reference; loading mechanics in component.cortex.domain-loading.

Pack Invariants

  1. Packs are JSON only. No executable content.
  2. Packs configure behavior; they do not implement it.
  3. Packs cannot bypass UDS ABAC.
  4. Packs are versioned (_v1, _v2, etc.).
  5. Accountability packs govern workflow. Experience packs govern UI. These concerns MUST NOT be mixed.
  6. Signal policy IDs in accountability packs MUST match actual policy definitions.
  7. Decision template IDs MUST reference templates that actually exist. OPEN GAP: no validation today.

Surface Behavior

Pages (OODA Mapping)

Page Route OODA Phase Primary Objects
Home /home Hub Navigation only
Monitor /monitor Observe Signals, KPIs
Explore /explore Orient Blocks, AI chat
Investigations /investigations/:insightId Decide Investigation with 4 tabs
Edition /edition/:editionId Decide Sealed edition (standalone)
Tasks /tasks Act Task queue

Legacy routes redirect: /inbox/tasks, /insights/investigations. Route params use :insightId (wire protocol name), not :investigationId.

Accountability Enforcement Timeline

Investigation start  → entry_modes[] checked (Cortex)
Evidence gathering   → no accountability checks (ABAC still applies at UDS layer)
Pin block            → no accountability checks (editorial action)
Create edition       → min_evidence enforced, allowed_decision_types checked (Cortex)
Freeze edition       → require_rationale enforced, content_hash computed (Cortex)
Request review       → OPTIONAL. default_reviewers used for assignment (Cortex)
Attest edition       → attester role checked, separation of duties enforced (Cortex)
                       SKIPPED for no-action decisions

Signal Filtering (Three Gates)

For a signal to reach a user, ALL three gates must pass (AND logic): (1) Policy ID ∈ user's accountability.signals.policies[]; (2) Signal severity ∈ user's accountability.signals.severity_filter[]; (3) Signal visibility_keys ∩ user's visibility_keys ≠ ∅.

Task Semantics

Tasks are the ONLY mechanism for human handoff. Worker-queue pattern, NOT a workflow engine: published to a queue for eligible workers; assigned by eligibility (role, group, user), not deterministic routing; no conditional branching, no auto-state-progression.

Surface Enforcement Gap

Surface event boundaries (which events each page may emit) are currently advisory only. Cortex does NOT validate source_surface on incoming events. A buggy or malicious frontend could emit block_created from Monitor or attested from Explore. Recommended fix: attach source_surface to every event and add server-side validation in Cortex. Until then, the allowed-events table in component.cortex.developer-rules#events-by-surface is a frontend correctness contract, not a security boundary.

Open Gaps

ID Gap Priority
G-01 No identity/SSO spec document High
G-02 Signal transition validation not implemented High
G-03 Template existence validation at pack load High
G-04 Decision Effects not implemented Medium
G-05 Escalation path not enforced in code Medium
G-12 deferred decision type has no template High
G-13 decision_attest vs edition_attest inconsistency Medium
G-14 Composite score computation status unknown Medium
G-15 Guardrails inheritance ambiguity (RM has no guardrails section) Medium

Depends on: component.cortex.decision-evidence, component.cortex.intelligence, component.cortex.pack-reference

Required by: component.cortex.developer-rules