Domain · Specifications

Iris Domain — Technical Specifications

1.

20sections41 minread

On this page

Technical specification for the Iris AI Assistant platform. Documents the shared type system, the runnable API surface, the conversation/memory/agent library clusters, persistence, events, configuration, and integration contracts as they exist in libs/iris/** and apps/iris/**.

Grounding rule: every entity, field, enum value, endpoint, and configuration key below is traceable to source. Items not yet implemented are labelled (planned). Where the prior draft asserted detail that does not exist in code, it has been removed.

This document is the authoritative source for what is actually implemented in the Iris codebase, as opposed to what is planned. It was written directly against the source files in libs/iris/types/src/, libs/iris/conversation-core/src/, libs/iris/conversation-orchestration/src/, libs/iris/agents/src/, libs/iris/core/src/config/, libs/iris/database/prisma/schema.prisma, apps/iris/api/src/, libs/shared/event-bus/src/, and the libs/iris/integrations/ packages. Package counts come from find libs/iris -name package.json (258) and find apps/iris -name package.json (11).

Several things asserted in earlier drafts were removed because they could not be traced to code: Kafka topics, the iris_* PostgreSQL tables, Qdrant collections, Redis cache-key tables, the WebSocket event catalog, Free/Pro/Enterprise plan-limit tiers, the model-routing decision matrix, and several environment variables. Every section that describes target-state infrastructure that is not yet wired is explicitly labelled as planned.


Table of Contents#

  1. Scope and Implementation Status
  2. Shared Type System (@iris/types)
  3. Conversation Domain Objects
  4. Memory Domain Objects
  5. Agent, Task, and Action Domain Objects
  6. Model and Provider Domain Objects
  7. Tool Domain Objects
  8. User, Session, and Preference Objects
  9. Event Type System
  10. Conversation Engine (@iris/conversation-core)
  11. HTTP / GraphQL API Surface (@iris/api)
  12. Persistence
  13. Configuration (@iris/config, @iris/core)
  14. Library Clusters
  15. Cross-Domain Integration Libraries
  16. Rollback-Safe In-Match Commentary Contract (V2 Consumer)
  17. V2 Accessibility Bridge Contract (V2 Consumer)
  18. V2 Mobile Companion App (V2 Consumer)
  19. Acceptance Criteria

1. Scope and Implementation Status#

Iris is partially implemented. The codebase is a large package tree:

  • libs/iris/**258 package.json files (Nx projects), organised into functional clusters (conversation, memory, knowledge, agents, code, privacy, platform, multimodal, emotional, accessibility, analytics, integrations, and foundation libraries).
  • apps/iris/**11 application package.json files: @iris/api, @iris/dashboard, @iris/desktop, @iris/developer-portal, @iris/marketplace, @iris/mobile, @iris/wearable-shared, @iris/browser-extension, @iris/pwa, @iris/widget, @iris/xr-shared.
  • There is no services/iris/ directory.

The most fully built-out, verifiable pieces — and the focus of the concrete sections of this document — are:

  • @iris/types — the shared domain type system (8 source modules with tests).
  • @iris/api — a runnable Hono REST + GraphQL service with conversation, memory, agent, and knowledge routes.
  • @iris/conversation-core — the dialogue engine: conversation manager, turn manager, context window, dialogue state machine.
  • @iris/conversation-orchestration — multi-model orchestration plus the V2 match-commentary contract.
  • @iris/agents — a mobile-safe built-in agent catalog.
  • @iris/core / @iris/config — foundation utilities and configuration.
  • libs/iris/database — a Prisma schema (3 models).

Many cluster leaf packages exist as Nx projects with their own src/; this document describes the ones whose contracts are load-bearing and verifiable. It does not claim production deployment, Kubernetes topology, or external infrastructure that is not present in the repository.


2. Shared Type System (@iris/types)#

libs/iris/types/src/ is the canonical domain vocabulary. All other Iris packages import their core types from here rather than defining them locally, which ensures that a ConversationId in the conversation engine is the same type as a ConversationId in the memory system. There are eight source modules, each with a co-located *.test.ts:

Module Defines
conversation.ts Conversations, messages, turns, threads, content blocks
memory.ts The four-tier memory model
agent.ts Agents, tasks, actions, executions, plans, multi-agent
model.ts Providers, models, requests, responses, streaming, costs
tool.ts Tool definitions, calls, executions, registry interfaces
user.ts Users, profiles, preferences, sessions, auth, quotas
events.ts Domain events, event bus / event store interfaces
index.ts Re-exports

Two conventions are used throughout the type system:

  • Branded ID types — every entity has its own opaque ID type (e.g. ConversationId, MessageId, AgentId) defined as string & { readonly [Brand]: ... }. This prevents accidentally passing a UserId where a ConversationId is expected. A create*Id() factory produces IDs in the form ${prefix}_${base36-timestamp}-${random} (e.g. conv_…, msg_…, agt_…). The full list: ConversationId, MessageId, ThreadId, TurnId, MemoryId, MemoryBlockId, MemoryChunkId, AgentId, TaskId, ActionId, ExecutionId, ToolId, ToolCallId, ToolExecutionId, UserId, SessionId, ProfileId, EventId, CorrelationId.
  • Zod schemas — most string-union types ship a paired …Schema (z.enum([...])) for runtime validation, so the same enum definition works for both TypeScript type checking and API request validation.

3. Conversation Domain Objects#

The conversation module defines the full lifecycle of a dialogue: from the top-level Conversation container through Thread (a branch of the conversation) down to individual Message objects and the ContentBlock[] array that carries the actual content. Every field is readonly on the core types, enforcing immutable records at the type level.

3.1 Conversation#

Conversation (all fields readonly):

Field Type Meaning
id ConversationId Branded conversation ID
title string? Optional title
description string? Optional description
ownerId string Owning user
status ConversationStatus Lifecycle status
config ConversationConfig Model, mode, sampling, tooling config
participants ParticipantState[] Participants with per-participant counts
threads Thread[] Branch threads
activeThreadId ThreadId? Currently active thread
stats ConversationStats Aggregate counters
createdAt Date Creation time
updatedAt Date Last update
lastMessageAt Date? Time of last message
metadata Record<string,…>? Arbitrary metadata

Related inputs: ConversationInput (create), ConversationUpdate (patch).

ConversationConfigmode (ConversationMode), model (string), provider?, systemPrompt?, temperature?, maxTokens?, topP?, topK?, stopSequences?, tools? (string IDs), contextWindow?, summarizationEnabled?, streamingEnabled?.

ConversationStatsmessageCount, turnCount, threadCount, participantCount, totalTokens, inputTokens, outputTokens, averageResponseMs?, topics?.

ConversationContext — assembled context for a model call: systemPrompt?, messages, tools?, summary?, contextWindow, totalTokens, truncated.

3.2 Message#

Message: id (MessageId), conversationId, threadId?, parentMessageId?, role (ParticipantRole), participantId, content (ContentBlock[]), status (MessageStatus), createdAt, updatedAt?, metadata? (MessageMetadata).

MessageMetadata: model?, provider?, stopReason? (FinishReason), tokenUsage? (TokenUsage), latencyMs?, cached?, plus open keys.

TokenUsage (conversation module): inputTokens, outputTokens, totalTokens, cacheReadTokens?, cacheWriteTokens?.

MessageDelta carries streaming updates with type of content_block_start, content_block_delta, content_block_stop, or message_delta.

3.3 Content Blocks#

ContentType union: text, image, audio, video, file, code, tool_use, tool_result. ContentBlock is the discriminated union of TextContent, ImageContent, AudioContent, VideoContent, FileContent, CodeContent, ToolUseContent, ToolResultContent. TextContent carries optional TextAnnotation[] (bold | italic | code | link | mention | highlight with startIndex/endIndex). Type guards: isTextContent, isImageContent, isToolUseContent, isToolResultContent; helpers extractText, textContent, normalizeContent.

3.4 Turn and Thread#

Turn: id (TurnId), conversationId, index, userMessage, assistantMessage?, toolUses? (ToolExchange[]), startedAt, completedAt?, durationMs?, tokenUsage?, metadata?. ToolExchange pairs a ToolUseContent with a ToolResultContent. TurnSummary is a compressed turn record (userIntent, assistantAction, outcome?, topics?, tokenCount).

Thread: id (ThreadId), conversationId, parentThreadId?, branchFromMessageId?, name?, description?, status (ThreadStatus), messageCount, createdAt, updatedAt, resolvedAt?, metadata?.

3.5 Conversation Enums#

The following enums define the status vocabulary for conversation, message, and thread lifecycle management. They are the values that appear in status fields throughout the REST API, GraphQL schema, and event payloads.

Enum Values
ParticipantRole user, assistant, system, tool, function
ContentType text, image, audio, video, file, code, tool_use, tool_result
MessageStatus pending, streaming, completed, failed, cancelled, filtered
FinishReason stop, length, tool_use, content_filter, error, cancelled
ThreadStatus active, resolved, archived, deleted
ConversationStatus active, paused, completed, archived, deleted
ConversationMode chat, completion, assistant, agent

3.6 Conversation Operations and Events#

Operation request/response types: SendMessageRequest/SendMessageResponse, RegenerateMessageRequest, BranchConversationRequest.

ConversationEventType (the type-module union): conversation.created, conversation.updated, conversation.deleted, message.created, message.updated, message.deleted, message.streaming, turn.started, turn.completed, thread.created, thread.resolved, participant.joined, participant.left. Event objects: ConversationEvent, MessageEvent, TurnEvent, ThreadEvent, union AnyConversationEvent.


4. Memory Domain Objects#

memory.ts documents itself as a MemGPT-inspired tiered memory model. The type module is the authoritative definition of the four-tier hierarchy; it is referenced by all 22 packages in libs/iris/memory/ and by the /api/v1/memory routes in @iris/api.

4.1 Memory Tiers and Classification#

MemoryTier defines four tiers: core, working, archival, episodic. Each tier has a distinct timescale and entry type, described in the subsections below.

The four-tier model is authoritative. A semantic tier and a long_term tier (named in an earlier draft) are not in the enum. "Semantic" retrieval is a property of archival memory (vector embeddings), not a separate tier; episodic memory covers long-term event history.

MemoryType — 13 values: persona, goal, preference, fact, event, conversation, entity, relationship, skill, instruction, context, summary, reflection.

MemoryImportancecritical, high, medium, low, trivial, with MEMORY_IMPORTANCE_VALUES mapping them to 100 / 75 / 50 / 25 / 10.

CoreMemorySectionpersona, user, system, goals.

4.2 Tier Entry Types#

Core memoryCoreMemoryBlock (id, section, content, maxTokens, currentTokens, timestamps); CoreMemoryConfig groups the persona/user/system/ goals blocks under a totalTokenBudget; CoreMemoryUpdate operations are replace | append | prepend | insert.

Working memoryWorkingMemoryEntry (id, type, content, relevance, recency, accessCount, timestamps, expiresAt?). WorkingMemoryConfig (maxEntries, maxTokens, decayRate, relevanceThreshold, ttlMs?). WorkingMemoryState bundles entries + config.

Archival memoryArchivalMemoryEntry (id, type, content, summary?, importance, embedding? (number[]), embeddingModel?, topics?, entities? (EntityReference[]), source? (MemorySource), timestamps, accessCount). ArchivalSearchQuery / ArchivalSearchResult (matchType: semantic | keyword | hybrid). ArchivalMemoryConfig: embeddingModel, embeddingDimensions, indexType (flat | hnsw | ivf), similarityMetric (cosine | euclidean | dot_product), autoSummarize, extractEntities.

Episodic memoryEpisodicMemoryEntry (id, eventType, timestamp, content, participants?, location?, emotion? (EmotionState), outcome?, relatedMemories?, conversationId?, turnId?). EpisodicEventType — 12 values: conversation_start, conversation_end, user_message, assistant_response, tool_use, error, milestone, decision, learning, preference_change, goal_update, context_switch. EmotionState: valence (-1..1), arousal (0..1), dominance?, label?.

4.3 Generic Memory, Chunks, Operations#

MemoryBlock is the tier-agnostic record (tier, type, content, importance, tokenCount, embedding?, references?, access counters). MemoryChunk and MemoryContext assemble tier content into an LLM context window under a token budget. MemoryContextConfig carries coreBudgetRatio / workingBudgetRatio / archivalBudgetRatio / episodicBudgetRatio.

MemoryOperationcreate, read, update, delete, search, summarize, merge, split, archive, restore. MemorySummary records a summarization with a compressionRatio.

4.4 Default Configurations#

These constants represent the out-of-box behavior when no explicit configuration is provided. The DEFAULT_MEMORY_CONTEXT_CONFIG budget ratios (core 15%, working 40%, archival 30%, episodic 15%) determine how the LLM context window is partitioned between tiers on each turn.

Constant Notable values
DEFAULT_WORKING_MEMORY_CONFIG maxEntries 100, maxTokens 8000, decayRate 0.95, relevanceThreshold 0.3, ttlMs 3600000
DEFAULT_ARCHIVAL_MEMORY_CONFIG embeddingModel 'text-embedding-3-small', embeddingDimensions 1536, indexType 'hnsw', similarityMetric 'cosine'
DEFAULT_MEMORY_CONTEXT_CONFIG tokenBudget 32000; budget ratios core 0.15 / working 0.4 / archival 0.3 / episodic 0.15

5. Agent, Task, and Action Domain Objects#

The agent module defines the runtime objects for autonomous task execution. An Agent holds configuration (what capabilities it has, which model it uses, what tools it can invoke) and a live AgentState (what it is currently doing, how many turns it has taken, any errors). A Task represents a unit of work assigned to an agent, and Action represents a single step within that task. The nesting is: one Agent → many Tasks → each Task has many Actions.

5.1 Agent#

AgentConfig: id (AgentId), name, description?, role (AgentRole), model, provider?, systemPrompt, capabilities (AgentCapability[]), tools?, maxTurns?, maxTokensPerTurn?, temperature?, topP?, stopSequences?, metadata?. AgentState adds runtime status, current task/ action, counters, errors (AgentError[]), metrics (AgentMetrics). Agent = config + state + timestamps.

DEFAULT_AGENT_CONFIGrole: 'assistant', capabilities: ['conversation','tool_use'], maxTurns: 20, temperature: 0.7.

5.2 Task and Action#

Task: id (TaskId), name, agentId, parentTaskId?, status, priority, input (TaskInput), output? (TaskOutput), actions (ActionRecord[]), dependencies?, blockedBy?, timestamps, timeoutMs?, retryCount, maxRetries. TaskInput type is text | structured | multimodal; TaskConstraints caps tokens/actions/duration and allows tool allow/forbid lists. TaskOutput may carry TaskArtifact[].

Action: id (ActionId), taskId, agentId, type (ActionType), name, input, status, result? (ActionResult), timing, retryCount. ActionResult may include ActionSideEffect[] (file_created, file_modified, file_deleted, memory_updated, state_changed, external_call, each with a reversible flag).

DEFAULT_TASK_CONSTRAINTSmaxTokens: 100000, maxActions: 50, maxDurationMs: 300000.

5.3 Execution, Delegation, Planning, Multi-Agent#

  • ExecutionExecutionContext (token budget, deadline, variables, tools, capabilities), ExecutionResult, ExecutionTrace / ExecutionTraceEntry (entry type: thought | action | observation | error | decision).
  • DelegationDelegationRequest / DelegationResult for agent-to-agent task handoff.
  • PlanningExecutionPlan (steps, dependencies, confidence, alternatives?), PlanStep, PlanDependency (requires | enables | blocks).
  • Multi-agentAgentTeam (coordinatorId, routingStrategy: round_robin | capability_based | load_balanced | custom), AgentMessage (request | response | notification | broadcast).

5.4 Agent Enums#

The following enums define the vocabulary for agent roles, lifecycle states, declared capabilities, and task/action status. Note that the runnable @iris/api agent route validates a different, route-local set of these values (see §11.3) — the API layer is not yet fully aligned to the types defined here.

Enum Values
AgentRole assistant, specialist, coordinator, executor, analyst, reviewer, custom
AgentStatus initializing, ready, busy, waiting, paused, error, terminated
AgentCapability conversation, tool_use, code_execution, file_access, web_access, memory_access, delegation, planning, reflection, learning
TaskStatus pending, queued, running, paused, completed, failed, cancelled, timeout
TaskPriority critical, high, normal, low, background (TASK_PRIORITY_VALUES 100/75/50/25/10)
ActionType tool_call, message, delegate, memory_operation, code_execution, file_operation, web_request, wait, decision, custom
ActionStatus pending, executing, completed, failed, cancelled, skipped

Note: the runnable @iris/api agent route validates a different, route-local set of capability/status enums (see §11.3) — the API layer is not yet aligned to @iris/types.

5.5 Built-In Agent Catalog (@iris/agents)#

libs/iris/agents/src/index.ts exports a static catalog used by V2 companion surfaces. IRIS_BUILT_IN_AGENT_IDS — 9 IDs: general, codeassist, researcher, writer, analyst, support, creative, operations, supervisor. Each IrisBuiltInAgentDescriptor carries label, specialty, summary, surfaces (web | mobile | desktop | service | game-companion), capabilities (IrisAgentCapability), defaultToolCategories (IrisAgentToolCategory), maxAutonomousSteps, requiresHumanReview, and implementationPackages. Exported functions: listIrisBuiltInAgents, getIrisBuiltInAgent, selectIrisAgentForIntent (intent-ordered selection over IrisAgentIntent), resolveIrisAgentsLaunchReadiness.

The descriptors delegate to implementation packages — @iris/agents-core, @iris/archetypes, @iris/multi-agent, @iris/workflows, and (for supervisor) @iris/agent-marketplace.


6. Model and Provider Domain Objects#

The model module defines the typed layer between Iris and AI providers. It gives every provider a uniform ModelDefinition shape so the model router (@iris/model-routing) can compare providers on price, context window, and capability without hardcoding provider-specific logic into the routing decision. The WELL_KNOWN_MODELS registry is the authoritative list of supported models with real pricing and context metadata.

6.1 Providers and Models#

ModelProvideranthropic, openai, google, cohere, mistral, groq, together, aws-bedrock, azure-openai, local, custom. ProviderStatusavailable, degraded, unavailable, unknown. ProviderConfig and ProviderHealth (latencyMs?, quotaRemaining?).

ModelDefinition: id, provider, name, displayName?, tier (ModelTier), capabilities (ModelCapability[]), contextWindow, maxOutputTokens, inputPricePerMToken, outputPricePerMToken, cachePricePerMToken?, embeddingDimensions?, dates, isDefault?.

ModelTierflagship, standard, fast, economy, embedding. ModelCapabilitychat, completion, embedding, vision, audio, video, function_calling, tool_use, streaming, json_mode, system_prompt, multi_turn, caching.

6.2 Model Registry (WELL_KNOWN_MODELS)#

The registry ships eight models with real pricing and context-window metadata. claude-sonnet-4 is the default (isDefault: true). MODEL_ALIASES maps short names like claude, gpt4, and gemini to their full model IDs so callers can use convenient names. The helpers resolveModelAlias, getModelDefinition, modelHasCapability, estimateCost, findModels, and getDefaultModel are the primary API for querying this registry.

Eight registered models with real pricing/context metadata:

Key Provider Tier Context Default
claude-opus-4-5 anthropic flagship 200K no
claude-sonnet-4 anthropic standard 200K yes
claude-haiku-3-5 anthropic fast 200K no
gpt-4o openai flagship 128K no
gpt-4o-mini openai fast 128K no
gemini-2-0-flash google fast 1M no
text-embedding-3-small openai embedding 8191 no
text-embedding-3-large openai embedding 8191 no

MODEL_ALIASES maps short names (claude, claude-opus, gpt4, gemini, embed-small, …) to model IDs. Helpers: resolveModelAlias, getModelDefinition, modelHasCapability, estimateCost, findModels, getDefaultModel.

6.3 Requests, Responses, Streaming, Cost#

ChatCompletionRequest (model, messages, tools?, toolChoice?, responseFormat?, sampling params, stream?), EmbeddingRequest, ChatCompletionResponse, EmbeddingResponse. StopReasonend_turn, stop_sequence, max_tokens, tool_use, content_filter, error. StreamEventTypemessage_start, content_block_start, content_block_delta, content_block_stop, message_delta, message_stop, error. Cost types: CostEstimate, UsageTracking (per-model and per-provider breakdowns). Caching: CacheControl (ephemeral | persistent), CachedContentBlock.


7. Tool Domain Objects#

The tool module defines the contract for everything an agent can invoke. A ToolDefinition declares what a tool does, what inputs it accepts (JSON-Schema-shaped), what risk level it carries, and what rate limits apply. A ToolSpecification is the trimmed version passed directly to an LLM (name, description, input_schema), containing only what the model needs to decide whether to call the tool. The registry and executor interfaces (IToolRegistry, IToolExecutor, IToolValidator) are the extension points for registering new tools.

ToolDefinition: id (ToolId), name, displayName?, description, category (ToolCategory), version, status (ToolStatus), riskLevel (ToolRiskLevel), inputSchema (ToolInputSchema, JSON-Schema-shaped), outputSchema?, examples?, permissions?, rateLimit? (ToolRateLimit), timeout?, retryConfig? (ToolRetryConfig), tags?. ToolSpecification is the trimmed shape passed to an LLM (name, description, input_schema).

Enum Values
ToolCategory code, file, web, data, communication, search, analysis, generation, memory, utility, custom
ToolRiskLevel safe, low, medium, high, critical
ToolStatus enabled, disabled, deprecated, experimental
ToolExecutionStatus pending, validating, executing, completed, failed, timeout, cancelled, rate_limited
FileOperation read, write, append, delete, list, copy, move
WebOperation fetch, search, scrape, screenshot
CodeOperation execute, analyze, format, lint, test

Execution types: ToolExecutionContext, ToolExecutionResult, ToolExecutionError (type: validation | execution | timeout | permission | rate_limit | unknown), ToolResult. Registry/executor interfaces: IToolRegistry, IToolExecutor, IToolValidator. Defaults: DEFAULT_TOOL_RETRY_CONFIG (maxRetries 3, initialDelayMs 1000, maxDelayMs 30000, backoffMultiplier 2), DEFAULT_TOOL_RATE_LIMIT (maxCallsPerMinute 60, maxCallsPerHour 1000, maxConcurrent 10), DEFAULT_TOOL_TIMEOUT = 30000.


8. User, Session, and Preference Objects#

The user module defines the core identity, authentication, and preference objects. User is the minimal identity record; UserProfile adds rich profile data. UserPreferences groups five preference namespaces (GeneralPreferences, AssistantPreferences, NotificationPreferences, PrivacyPreferences, AccessibilityPreferences) under a single object, each with a DEFAULT_* constant and a createDefaultPreferences(userId) factory. IrisJwtClaims defines the token payload for JWT-authenticated sessions.

User: id (UserId), email, username?, displayName, name fields, avatarUrl?, status (UserStatus), role (UserRole), accountType (AccountType), organizationId?, teamIds?, permissions?, timestamps. UserProfile adds bio/location/social/expertise plus language, timezone, locale.

Enum Values
UserStatus active, inactive, pending, suspended, deleted
UserRole user, premium, admin, system
AccountType individual, team, enterprise
ThemePreference light, dark, system
VoiceStyle natural, professional, friendly, concise
ResponseLength brief, moderate, detailed, comprehensive
SessionStatus active, idle, expired, revoked
DeviceType desktop, mobile, tablet, unknown
AuthMethod password, oauth, sso, api_key, magic_link
OAuthProvider google, github, microsoft, apple, facebook
UsagePeriod hour, day, week, month

UserPreferences groups GeneralPreferences, AssistantPreferences, NotificationPreferences, PrivacyPreferences, AccessibilityPreferences. AssistantPreferences includes defaultModel?, voiceStyle, responseLength, showThinking, streamResponses, rememberContext, contextRetentionDays, preferredTools?, disabledTools?. Each preference group ships a DEFAULT_* constant and createDefaultPreferences(userId) assembles them.

Authentication: AuthContext, IrisJwtClaims (sub, userId, sessionId, email, roles, permissions?, iat/exp/iss/aud), LoginRequest, LoginResponse. Quotas: UserQuota (conversation/message/token/apiCall/storage limits + used counters), UsageStats. Guard isQuotaExceeded compares used vs. limit across all five quota dimensions.

Quota limits are fields on UserQuota records; they are not hard-coded plan tiers anywhere in libs/iris. There is no per-plan limits table in code; an earlier draft's "Free/Pro/Enterprise" table has been dropped.


9. Event Type System#

The event module defines the type-level contracts for how Iris components notify each other about state changes. It uses a CloudEvents-inspired envelope that carries routing metadata (category, aggregate, correlation ID, trace IDs) separately from the event payload. This lets consumers filter and route events based on the envelope alone, without deserializing the payload.

Note that this module defines TypeScript interfaces, not a running message broker. The shared runtime transport is the @oshun/event-bus (see §12.3), and no libs/iris package currently publishes events onto it. The types here are the agreed contract for when publishing is implemented.

events.ts defines a CloudEvents-style domain-event model. DomainEvent<T>: id (EventId), type (string), category (EventCategory), aggregateId, aggregateType, payload, metadata (EventMetadata), occurredAt, sequenceNumber?. EventMetadata carries correlationId, causationId?, source, version, timestamp, optional userId/sessionId/agentId/ traceId/spanId/tags/context.

EventCategoryconversation, message, agent, task, memory, user, session, system, tool, model, error. EventSeveritydebug, info, warning, error, critical.

The IrisEventType union is composed from per-category unions. Representative members (string literals defined in code):

Category Event types (literal type strings)
Conversation conversation.created/updated/deleted/archived/restored
Message message.created/updated/deleted, message.streaming.started/delta/completed/error
Agent agent.created/updated/deleted/started/stopped/paused/resumed/error
Task task.created/started/completed/failed/cancelled/paused/resumed/progress
Memory memory.created/updated/deleted/accessed/summarized/compacted/promoted/demoted
Tool tool.registered/unregistered/called/completed/failed/timeout
Model model.request.started/completed/failed/rate_limited, model.stream.started/chunk/completed
User user.created/updated/deleted/activated/deactivated, user.preferences.updated
Session session.created/refreshed/expired/revoked
System system.started/stopped, system.health.changed, system.config.updated, system.maintenance.started/completed
Error error.occurred/recovered/escalated

Typed payloads exist for the principal events (ConversationCreatedPayload, MessageCreatedPayload, TaskCompletedPayload, MemoryCreatedPayload, ToolCalledPayload, ModelRequestCompletedPayload, …).

Interfaces IEventBus (publish, publishBatch, subscribe, unsubscribe, getSubscriptionCount) and IEventStore (append, getEvents, getEventsByType, getLatestEvent) define the bus/store contracts, plus event-replay types. Factories: createEventMetadata, createDomainEvent, createEventId, createCorrelationId.

These are type-level contracts in @iris/types. They are not the same as the shared @oshun/event-bus runtime (see §12.3); no libs/iris package currently publishes domain events onto a broker, and there are no Kafka topics — the prior draft's Kafka topic table was unfounded.


10. Conversation Engine (@iris/conversation-core)#

@iris/conversation-core is one of the most fully built-out packages in the iris codebase. It implements the core dialogue runtime: a state machine that tracks every conversation from idle through generating to completed, a context window manager that assembles and truncates the message history to fit within token budgets, and a conversation manager that handles persistence, branching, incognito mode, search indexing, snapshots, and export.

libs/iris/conversation-core/src/ is the dialogue engine. Public exports (index.ts) include createConversationManager, createContextWindow, createDialogueStateMachine, plus turn and history managers.

10.1 Dialogue State Machine#

The dialogue state machine is the heart of the conversation engine. It enforces that a conversation can only move between states through defined transitions — for example, you cannot jump from idle directly to streaming without going through processing and generating. This makes it impossible for a bug to leave a conversation stuck in an intermediate state silently.

DialogueStateType defines 11 states: idle, awaiting_input, processing, generating, streaming, tool_executing, awaiting_tool_result, completed, error, paused, terminated.

DialogueEvent — discriminated union driving transitions: USER_MESSAGE, SYSTEM_MESSAGE, START_GENERATION, START_STREAMING, STREAM_CHUNK, STREAM_COMPLETE, GENERATION_COMPLETE, TOOL_CALL, TOOL_RESULT, ERROR, PAUSE, RESUME, TERMINATE, RESET.

A static STATE_TRANSITIONS table (dialogue-state.ts) maps each state to its allowed (event → next state) pairs. Representative edges: idle --USER_MESSAGE--> processing; processing --START_GENERATION--> generating; generating --TOOL_CALL--> tool_executing; streaming --STREAM_COMPLETE--> completed; any non-terminal state --ERROR--> error and --TERMINATE--> terminated. StateTransitionResult records success, fromState, toState, event, and an error string on a rejected transition. DialogueStateData tracks previousState, transitionCount, pendingToolCalls, and streamingState.

10.2 Context Window#

ContextWindowConfigmaxTokens, systemPromptReserved, responseReserved, enableSummarization, summarizationThreshold (0–1 ratio), maxMessagesBeforeSummarize, minMessagesToKeep, enableTruncation, truncationStrategy (oldest_first | least_important | smart), charsPerToken. ContextWindowState and ContextAddResult report token accounting and whether summarization/truncation occurred. ContextOptimizationOptions / OptimizedContextResult describe budget-aware message selection with per-role weights and optional focus terms.

10.3 Conversation Manager and Sessions#

ConversationManagerConfig controls persistence, auto-save interval, in-memory cap, branching, search, export, and a default incognito policy. ConversationSession bundles a MutableConversation, DialogueStateData, ContextWindowState, the active/all turns (TurnState), and session metadata. CreateConversationOptions accepts incognito?: boolean | ConversationIncognitoEnableOptions.

Incognito modeConversationIncognitoPolicy toggles disablePersistence, disableSearchIndexing, disableExport, disableSnapshots, disableBookmarks, disableTagging, scrubMessageMetadata. ConversationIncognitoMode records the active mode (enabledAt, reason?, expiresAt?, policy).

TurnManagerConfig caps concurrent tool calls, tool-execution timeout, retries, and toggles turn summaries. TurnState tracks activeToolCalls / completedToolCalls maps and a token accumulator.

10.4 History, Snapshots, Export#

ConversationSnapshot captures dialogue/context/stats state for rollback, with reason of auto | manual | before_tool | before_branch | error_recovery. RollbackResult reports removed messages/turns. ConversationStorage is the storage-adapter interface (save/load conversations, messages, turns, snapshots). ConversationExportPayload / ConversationImportResult define portable export bundles (format: object | json).

10.5 Conversation Engine Events#

ConversationEngineEvent is the engine-internal event union (distinct from the @iris/types events.ts model). Members include conversation.created/ updated/deleted, conversation.incognito_enabled/disabled, message.created/updated/streaming/completed, turn.started/completed/failed, tool.called/completed, state.changed, context.summarized/truncated, snapshot.created, rollback.completed, thread.created/switched, error.

Other conversation-core source files: context-window.ts, conversation-manager.ts, conversation-history.ts, turn-manager.ts, streaming-response-generator.ts, conversation-search-index.ts, conversation-bookmarks.ts, conversation-tags.ts, conversation-highlights.ts, conversation-sharing.ts, conversation-analytics-tracker.ts, in-memory-conversation-storage.ts.


11. HTTP / GraphQL API Surface (@iris/api)#

@iris/api is the only runnable service in the iris codebase today. It is a single Hono process that hosts all route groups — conversation, memory, agent, knowledge, GraphQL, health, and docs — under one process on port 3100 (default). Authentication is not yet implemented; every route resolves the user via a getUserId() placeholder returning 'user-001'. Rate limiting is applied per-route using preset tiers (readonly, standard, heavy, streaming, search).

apps/iris/api/ is a runnable Hono service. src/index.ts wires global middleware (request-id, distributed tracing, secureHeaders, CORS, request logging, response timing), mounts the route groups, and serves on PORT (default 3100). Logging and tracing are initialised from env via @iris/core/logging and @iris/core/tracing.

Mount points:

Base path Router
/health healthRoutes
/api/v1/conversations conversationRoutes
/api/v1/memory memoryRoutes
/api/v1/agents agentRoutes
/api/v1/knowledge knowledgeRoutes
/graphql GraphQL handler (playground enabled)
/docs docsRoutes (OpenAPI + code samples)
/ Service info JSON

All routes apply a per-route rateLimiter preset (readonly, standard, heavy, streaming, search). Request bodies are validated with @hono/zod-validator. Authentication is not yet implemented — every route resolves the user via a getUserId() placeholder returning 'user-001'.

11.1 Health Endpoints#

Method Path Description
GET /health Basic liveness JSON (status, service, version)
GET /health/live Liveness probe ({ status: 'alive' })
GET /health/ready Readiness probe — real Postgres + Redis health round-trips via @oshun/database; 503 if a subsystem is unhealthy
GET /health/detailed Runtime + process memory metrics

11.2 Conversation Endpoints (/api/v1/conversations)#

Method Path Description
GET / List (paginated; status, search, sortBy, sortOrder query params)
POST / Create (CreateConversationSchema)
GET /:id Get by ID
PATCH /:id Update title / systemPrompt / settings / metadata
DELETE /:id Delete
POST /:id/archive Archive
POST /:id/branch/:messageId Branch from a message
GET /stats/summary Per-user conversation stats
POST /:id/messages Send a message, returns user + assistant message
GET /:id/messages List messages (limit, before, after)
POST /:id/regenerate Regenerate last assistant response
POST /:id/stream Stream a response via Server-Sent Events

CreateConversationSchema: title?, systemPrompt?, model (default claude-3-5-sonnet-20241022), settings? (temperature default 0.7 [0–2], maxTokens default 4096 [1–100000], topP?, presencePenalty?, frequencyPenalty?), metadata?. SendMessageSchema: content (1–100000 chars), role (user | system, default user), optional contentBlocks (type ∈ text|image|audio|code|tool_use|tool_result), metadata?, parentMessageId?.

11.3 Agent Endpoints (/api/v1/agents)#

Agent CRUD plus enable/disable/stats, per-agent tool management, and tasks:

Method Path Description
GET / POST / List / create agents
GET / PATCH / DELETE /:id Get / update / delete an agent
POST /:id/enable, /:id/disable Enable / disable an agent
GET /:id/stats Agent statistics
GET / POST /:id/tools List / add agent tools
DELETE / PATCH /:id/tools/:toolName Remove / enable-disable a tool
GET / POST /tasks List / create tasks
GET /tasks/:taskId Get a task
POST /tasks/:taskId/{run,pause,resume,cancel} Task lifecycle
GET /:id/tasks List tasks for one agent

Route-local validation enums (note: not the @iris/types enums): agent statusidle, running, paused, error, completed, disabled; capabilitiesconversation, code_generation, code_execution, web_search, file_operations, tool_use, memory_access, delegation, planning, reasoning; task prioritycritical, high, medium, low; task statuspending, queued, running, paused, completed, failed, cancelled.

11.4 Memory Endpoints (/api/v1/memory)#

Tier-segmented routes plus generic memory CRUD:

Method Path Description
GET /core All core memory blocks
GET / PUT /core/:section Get / replace a core block
POST /core/:section/append Append to a core block
GET /working/:sessionId Working memory for a session
POST /working Add a working-memory entry
DELETE /working/:sessionId Clear a session's working memory
GET /archival/search Search archival memory
GET / POST /archival List / add archival entries
GET / POST /episodic List / record episodic events
POST / Create a memory of any tier
GET / PATCH / DELETE /:id Get / update / delete a memory
POST /search Cross-tier semantic search
GET /stats/summary Memory statistics
POST /cleanup Delete expired memories

CreateMemorySchema validates tiercore, working, archival, episodic; type against the 13-value MemoryType enum; importance against critical, high, medium, low, trivial. Note the route's core-section validation accepts persona, human, goals, instructions, custom — the runnable API uses human where @iris/types CoreMemorySection uses user; the API layer is not yet fully aligned to the type module.

11.5 Knowledge Endpoints (/api/v1/knowledge)#

Knowledge bases, documents, chunks, and search/RAG:

Method Path Description
GET / POST / List / create knowledge bases
GET / PATCH / DELETE /:id KB get / update / delete
GET / POST /:id/documents List / add documents
GET / PATCH / DELETE /:id/documents/:documentId Document get / update / delete
GET /:id/documents/:documentId/chunks List a document's chunks
POST /search Search across knowledge bases
GET /search Quick GET search (q, kb)
POST /rag Build RAG context for a query
GET /:id/stats KB statistics

Document typetext, markdown, pdf, html, code, json, csv, spreadsheet; document statuspending, processing, indexed, failed, archived; document source.typeupload, url, api, integration. KB settings allow chunkSize (100–2000), chunkOverlap (0–200), embeddingModel, maxDocuments, maxChunksPerDocument, autoReindex. RAG: maxChunks (1–20), maxTokens (100–16000), minScore (0–1).

11.6 GraphQL API (/graphql)#

src/graphql/schema.ts defines an SDL schema served with a playground.

  • Enums include ConversationStatus, MessageRole, AttachmentType (FILE, IMAGE, AUDIO, VIDEO, CODE), ToolCallStatus, TaskStatus, TaskStepType (THINKING, TOOL_CALL, TOOL_RESULT, RESPONSE), TaskStepStatus, MemoryTier (CORE, WORKING, ARCHIVAL, EPISODIC), MemoryType, and others.
  • Query fields — conversation/conversations, message/messages, agent/agents, task/tasks, coreMemory/coreMemoryBlock, and the knowledge queries; list queries use Relay-style connections.
  • Mutation fields — conversation, message, agent, task, memory, and knowledge mutations (e.g. createConversation, sendMessage, regenerateMessage, createAgent, runTask, updateCoreMemory, addToArchival, recordEpisodicEvent, createKnowledgeBase, addDocument, reindexKnowledgeBase).
  • Subscription fields — messageStream, conversationUpdated, agentUpdated, taskUpdated.

Supporting GraphQL files: resolvers.ts, data-loaders.ts, service-data-sources.ts, types.ts.


12. Persistence#

Understanding how Iris stores data is critical for anyone working on the service. There are two distinct storage mechanisms that must not be confused: (1) the Prisma schema in libs/iris/database, which defines the PostgreSQL tables for governance data (consent, continuity, memory scope); and (2) the DurableJsonStateStore used by @iris/api services, which stores conversation and agent state in in-memory Maps backed by a local JSON file. The in-memory store is not a database — it is a development-stage durability mechanism that will be replaced with PostgreSQL persistence as the service matures.

12.1 Prisma Schema (libs/iris/database)#

libs/iris/database/prisma/schema.prisma targets PostgreSQL via the IRIS_DATABASE_URL env var and generates a Prisma client to ../src/generated/client. It defines exactly three models:

ConsentRecord (consent_records) — a consent ledger entry. Fields: id (UUID), slug (unique), title, summary, description?, primaryDomain, domains[], subject (JSON), category, status, target (JSON), version, legalBasis/collection/verification (JSON), permissions/evidence (JSON arrays), the request/decision/grant/deny/ withdraw/revoke timestamps, expiresAt?, renewalRequired, renewalRequestedAt?, supersededById?, history (JSON), metadata (JSON), createdAt/updatedAt. Indexed on (primaryDomain,status), (status,requestedAt), expiresAt, supersededById.

ContinuityState (continuity_states) — per-user cross-domain continuity snapshot. Fields: id, userId (UUID), summary, primaryDomain, domains[], recentDomains[], status, momentum, focusTheme? (JSON), currentIntent?, streakDays, activeJourneyCount, reminderCount, lastActivityAt?, lastComputedAt, journeys/routeSnapshots/reminders/ checkpoints (JSON arrays), assistantState? (JSON), timestamps. Indexed on userId, (primaryDomain,status), (status,lastComputedAt), lastActivityAt.

MemoryScope (memory_scopes) — a named, governed memory boundary. Fields: id, slug (unique), title, summary, description?, primaryDomain, domains[], status, kind, mode, owner (JSON), priority, isDefault, boundary/retention/consent/sharing/ userControls/governance (JSON), runtimeMappings (JSON array), linkedPersonaIds[], tags[], metadata (JSON), timestamps. Indexed on slug, (primaryDomain,status), (status,priority), isDefault.

The Prisma schema does not define iris_conversations, iris_messages, iris_memories, iris_knowledge_documents, or iris_knowledge_chunks. Those tables, and the Qdrant/Redis cache-key tables described in an earlier draft, do not exist in code and have been removed.

12.2 API Service Storage#

The @iris/api services (conversation.service.ts, memory.service.ts, agent.service.ts, knowledge.service.ts) hold all state in in-memory Maps keyed by branded IDs (e.g. conversations: Map<ConversationId, StoredConversation>, with userConversations, agentTasks, documentChunks, etc. as secondary indexes).

Durability is provided by DurableJsonStateStore<T> (src/services/durable-json-state.ts): an atomic JSON-file snapshot store that writes to a ${pid}.${timestamp}.tmp file and renameSyncs it into place, loading on startup. It is file-backed JSON state, not a database. The /health/ready probe is the only place the API touches PostgreSQL/Redis, and only to check connectivity through @oshun/database.

12.3 Event Transport#

The shared @oshun/event-bus library (libs/shared/event-bus) is Redis-backed, not Kafka. event-bus.ts opens two ioredis connections (publisher + subscriber): publish() serialises an envelope into a TTL-bounded Redis key and fans it out over Redis pub/sub; a Redis HASH tracks acked (eventId, subscriptionId | group) pairs; nack(delay) and delayed publish use a durable Redis sorted set; dead letters live in a Redis list + hash. Consumer groups race via SET NX claim keys.

No libs/iris package currently publishes onto this bus, and there is no Kafka broker anywhere in the iris tree.


13. Configuration (@iris/config, @iris/core)#

All Iris service configuration is managed through a Zod-validated schema tree defined in libs/iris/core/src/config/schemas.ts. This means configuration errors are caught at startup rather than at runtime, and every config key has an explicit type. The loader (loader.ts) reads from environment variables, populating the schema with default values where variables are absent.

13.1 Configuration Schema#

libs/iris/core/src/config/schemas.ts defines the Zod-validated configuration tree (irisConfigSchema → IrisConfig):

  • servicename (default iris), version, environment (development | staging | production | test), instanceId?.
  • logginglevel (trace | debug | info | warn | error | fatal | silent), pretty?, redactPaths?, includeTimestamp, enableTracing.
  • contextdefaultTimeoutMs (30000), maxContextDepth (10), propagateHeaders.
  • providers — per-provider config objects for anthropic, openai, google, cohere, mistral, local; defaultProvider (default anthropic).
  • agents — array of agentConfigSchema entries.
  • memoryenabled, provider (in-memory | redis | postgres | vector-db, default in-memory), maxSize (1000), ttlMs?, optional embeddings block.
  • conversationmaxTurns (100), maxTokensPerMessage?, contextWindow (128000), persistMessages (default false), optional summarization block.
  • tools — array of toolConfigSchema entries.

Provider defaults: Anthropic claude-3-5-sonnet-20241022, OpenAI gpt-4-turbo, Google gemini-1.5-pro / us-central1, Cohere command-r-plus, Mistral mistral-large-latest; all HTTP providers default to a 120000 ms timeout and 3 retries.

13.2 Environment Variables#

libs/iris/core/src/config/loader.ts reads configuration from the environment (it accepts a custom env object, defaulting to process.env). The table below lists every variable that the loader actually reads — as verified against source. Variables listed in earlier documentation drafts that are not read in code (e.g. IRIS_QDRANT_URL, IRIS_KAFKA_BROKERS, IRIS_JWT_SECRET) have been removed from this table.

Keys actually read:

Variable Purpose
NODE_ENV Environment selection
SERVICE_NAME, SERVICE_VERSION, INSTANCE_ID Service identity
LOG_LEVEL, LOG_PRETTY, LOG_TIMESTAMP, LOG_REDACT_PATHS Logging
IRIS_ENABLE_TRACING Enable tracing in logging config
IRIS_DEFAULT_TIMEOUT_MS, IRIS_MAX_CONTEXT_DEPTH, IRIS_PROPAGATE_HEADERS Context
IRIS_DEFAULT_PROVIDER Default model provider
ANTHROPIC_API_KEY, ANTHROPIC_BASE_URL, ANTHROPIC_MODEL, ANTHROPIC_MAX_TOKENS, ANTHROPIC_TEMPERATURE, ANTHROPIC_TIMEOUT, ANTHROPIC_MAX_RETRIES Anthropic
OPENAI_API_KEY, OPENAI_ORGANIZATION, OPENAI_BASE_URL, OPENAI_MODEL, OPENAI_MAX_TOKENS, OPENAI_TEMPERATURE, OPENAI_TIMEOUT, OPENAI_MAX_RETRIES OpenAI
GOOGLE_AI_API_KEY, GOOGLE_AI_PROJECT, GOOGLE_AI_LOCATION, GOOGLE_AI_MODEL, GOOGLE_AI_MAX_TOKENS, GOOGLE_AI_TEMPERATURE, GOOGLE_AI_TIMEOUT Google AI
IRIS_MEMORY_ENABLED, IRIS_MEMORY_PROVIDER, IRIS_MEMORY_MAX_SIZE, IRIS_MEMORY_TTL_MS Memory
IRIS_EMBEDDINGS_ENABLED, IRIS_EMBEDDINGS_PROVIDER, IRIS_EMBEDDINGS_MODEL, IRIS_EMBEDDINGS_DIMENSIONS Embeddings
IRIS_CONVERSATION_MAX_TURNS, IRIS_CONVERSATION_MAX_TOKENS_PER_MESSAGE, IRIS_CONVERSATION_CONTEXT_WINDOW, IRIS_CONVERSATION_PERSIST Conversation
IRIS_SUMMARIZATION_ENABLED, IRIS_SUMMARIZATION_THRESHOLD, IRIS_SUMMARIZATION_MODEL Summarization

The @iris/api service additionally reads PORT (default 3100), CORS_ORIGINS, OTEL_SERVICE_NAME / IRIS_SERVICE_NAME, NODE_ENV, and the POSTGRES_* / REDIS_* / DB_* variables consumed by @oshun/database for its health probes.

Cohere and Mistral have config schemas but no dedicated *_API_KEY loader branch in loader.ts. There is no IRIS_QDRANT_URL, IRIS_MINIO_*, IRIS_KAFKA_BROKERS, IRIS_ENCRYPTION_KEY, or IRIS_JWT_SECRET consumed in code — the prior draft's environment table listed variables that are not read anywhere.

13.3 Error Codes#

libs/iris/core/src/errors/codes.ts defines a numeric error-code taxonomy (~92 codes) grouped by range: general (1000–1099), validation (1100–1199), auth (1200–1299), resource (1300–1399), context (1400–1499), conversation (1500–1599), agent (1600–1699), model/provider (1700–1799), memory (1800–1899), configuration (1900–1999), external service (2000–2099). It also maps codes to HTTP statuses. errors/base.ts defines the base error classes used across @iris/core.

@iris/core also provides request context, structured logging (Pino-based), and OpenTelemetry-style tracing (correlation, decorators, profiler, tracer).


14. Library Clusters#

libs/iris/** is organised into clusters, each covering a distinct functional area. The package counts below are derived from package.json files actually on disk — not from directory listings — so they are authoritative. Some package names do not match their directory path; where this is true, the package.json name field is the correct identifier, not the path.

14.1 Conversation Cluster#

There are 31 @iris/conversation*-named packages. They fall into two groups:

  • Top-level conversation-* packages (15): @iris/conversation-core, conversation-context, conversation-intent, conversation-state, conversation-response, conversation-rag, conversation-style, conversation-format, conversation-citations, conversation-uncertainty, conversation-orchestration, and the four provider adapters (conversation-providers-anthropic, -google, -local, -openai).
  • libs/iris/conversation/ subdirectory packages (16): the umbrella @iris/conversation plus conversation-benchmarking, conversation-branching, conversation-costs, conversation-export, conversation-finetuning, conversation-prompts, conversation-search, conversation-summarization, conversation-templates, conversation-tokens, and the six reasoning packages under conversation/reasoning/ (@iris/code-reasoning, @iris/consistency, @iris/math-reasoning, @iris/metacognition, @iris/scientific-reasoning, @iris/structured-reasoning).

Earlier docs described "10 conversation-_ libs" — the real count is far higher, and the two-group layout (sibling conversation-_directories vs. children ofconversation/) is itself a notable structural fact.

14.2 Memory Cluster#

libs/iris/memory/ contains 22 package.json files: @iris/memory-core, memory-short-term, memory-long-term, memory-episodic, memory-semantic, memory-working-equivalent state lives under memory-transitions / memory-consolidation, plus memory-retrieval, memory-persistence, memory-analytics, memory-debugging, memory-migration, memory-sharing, memory-tools, memory-visualization, memory-writing, and a memory/personalization/ sub-tree (@iris/personalization, personalization-feedback, -inference, -segments, -testing) and @iris/privacy (memory/privacy).

The earlier "7 memory-* libs" figure is wrong; the directory holds 22 packages. Note also @iris/memory-working does not exist as a package — working-memory behaviour is split across memory-transitions, memory-consolidation, and the tier types in @iris/types.

14.3 Other Clusters#

Cluster Representative packages
knowledge/ (~23) @iris/knowledge (core), knowledge-chunking, knowledge-embeddings, knowledge-retrieval, knowledge-rag (+ rag/ sub-tree: agentic-rag, rag-multimodal, rag-evaluation, rag-debugging, rag-adaptive-chunking), knowledge-graph, knowledge-graphrag, knowledge-factcheck, knowledge-grounding, knowledge-realtime, knowledge-curation, knowledge-enterprise, knowledge-personal, knowledge-versioning, knowledge-export, knowledge-query, knowledge-freshness, knowledge-types
agents/ @iris/agents (catalog), agents-core, @iris/archetypes, @iris/multi-agent (+ multi-agent-memory), @iris/agent-personalities, @iris/agent-marketplace, @iris/agent-specialization, @iris/workflows, the agents/proactive/ packages (ambient, anticipation, automation, reminders), the agents/tools/ registry (api-tools, code-tools, database-tools, filesystem-tools, web-tools, function-calling, tool-auth, tool-composition, tool-marketplace, tool-monitoring, tools-registry, tool-versioning, learning-tools), and the agents/computer-use/ packages (@iris/computer-use, @iris/browser-automation, @iris/desktop-automation, @iris/sandbox, @iris/action-safety, @iris/screenshot-vision, @oshun/iris-computer-use-native, computer-use-recording, -recovery, -templates, -accessibility)
code/ @iris/code-generation, code-review, code-explanation, code-understanding, code-architecture, code-codebase, code-dependencies, code-semantic, code-search, code-quality, code-metrics, code-consistency, code-languages, code-git, code-agentic, code-cli, code-turbo-mode, code-memory-persistence, code-repository-intelligence, and the code/ide/ packages (code-ide, -actions, -completions, -hover, -inline)
multimodal/ @iris/voice (multimodal/voice/recognition) and the voice/ family (voice-synthesis, voice-conversation, voice-commands, voice-auth, voice-effects, voice-journaling, voice-pronunciation), @iris/multimodal/vision and the vision/ family (vision-understanding, vision-documents, vision-diagrams, vision-generation, vision-screenshare, vision-search, vision-video, vision-memory), @iris/iot, @iris/spatial, @iris/bci
voice/ (top-level) @iris/voice-providers, @iris/voice-empathic-synthesis, @iris/voice-ultra-low-latency
emotional/ emotional-recognition, emotional-response, emotional-rapport, emotional-social, emotional-ethics, emotional-tracking, emotional-wellbeing, emotional-voice-analysis, emotional-multimodal-fusion
privacy/ privacy (umbrella, at memory/privacy) plus the privacy/ tree: privacy-encryption, privacy-local, privacy-anonymization, privacy-minimization, privacy-audit, privacy-access, privacy-secrets, privacy-sovereignty, privacy-communication, privacy-dashboard, privacy-private-cloud, privacy-third-party-consent, privacy-tiered-compute, and the privacy/safety/ and privacy/security/ sub-trees
platform/ platform-admin, platform-billing, platform-gateway, platform-ratelimit, platform-reporting, platform-codegen, platform-sla / platform-sla-management, platform-webhooks, @iris/streaming, @iris/plugins, the platform/customization/ packages (@iris/agent-builder, @iris/whitelabel), and the platform/sdk-* packages
accessibility/ accessibility (umbrella), accessibility-visual (+ -display, -alternatives), accessibility-motor, accessibility-hearing, accessibility-cognitive, accessibility-braille, accessibility-i18n, accessibility-voice-ui, accessibility-adaptive, accessibility-testing
analytics/ analytics (umbrella), analytics-realtime, analytics-cohort, analytics-funnel, analytics-ab
personalization/ (top-level) personalization-benchmarking, personalization-state-aware, personalization-user-model-persistence
bci/ (top-level) bci-apple-hid, bci-intent-prediction-api, bci-privacy-framework
testing/ testing (umbrella), testing-chaos, testing-load, testing-synthetic, testing-visual
Foundation @iris/core, @iris/types, @iris/config, @iris/embeddings, @iris/model-routing, @iris/ensemble, @iris/failover, @iris/mcp, @iris/a2a, @iris/reasoning-thinking, @iris/concordia-assistant, @iris/sdk (sdk/typescript), libs/iris/database (Prisma schema), presence (presence-sync, presence-integration)

Some package names do not carry an @iris/ prefix or do not match their directory path (e.g. @iris/knowledge lives at knowledge/core, @iris/voice lives at multimodal/voice/recognition, @oshun/iris-computer-use-native lives under agents/computer-use/native/ts, @iris/privacy lives at memory/privacy). Treat the package.json name field as authoritative.


15. Cross-Domain Integration Libraries#

libs/iris/integrations/ contains six packages, one per sister Oshun domain — they are cross-Oshun-domain bridges, not third-party SaaS connectors. Each package encapsulates the typed API surface that Iris exposes to a specific consuming domain, so that domain can depend on a stable contract without importing from @iris/api internals directly. The @iris/integrations-psyche package is the most developed example: it exports ./avatar, ./emotion, ./conferencing, and ./agents sub-paths, with only eventemitter3 and zod as runtime dependencies.

Package Bridges Iris to Stated purpose
@iris/integrations-hathor Hathor Worldbuilding integration
@iris/integrations-maya Maya Metaverse-engine integration
@iris/integrations-nyx Nyx Astronomy integration
@iris/integrations-psyche Psyche AI avatar representation, emotion expression, conferencing presence
@iris/integrations-sophia Sophia Research & knowledge integration
@iris/integrations-yemaya Yemaya Creative Studio integration

There is no top-level @iris/integrations package, and no Slack / Microsoft Teams / Notion / Jira / GitHub / Confluence connector exists anywhere in libs/iris. The @iris/integrations-psyche agent classes exported from ./agents include avatar-presenter-agent, conference-participant-agent, emotion-controller-agent, and persona-manager-agent.


16. Rollback-Safe In-Match Commentary Contract (V2 Consumer)#

The V2 fighting-game project (V2/) consumes Iris for AI play-by-play commentary during live matches. This section documents a specialized Iris API contract that is entirely distinct from the standard conversation API.

The fundamental engineering challenge is that V2's combat simulation uses rollback networking for lag compensation: when a desync is detected, the engine rolls back game state and re-simulates from the divergence point. Any LLM call made from inside the rollback bubble would be non-deterministic on the re-sim, corrupting replay files and breaking reconciliation between peers. Iris therefore exposes an in-match commentary contract with hard guarantees that LLM calls originate only from outside the rollback boundary and that commentary outputs never feed game state.

Implementation: createMatchCommentaryStream is implemented in libs/iris/conversation-orchestration/src/match-commentary.ts and re-exported from that package's index.ts (verified on disk, with a co-located match-commentary.spec.ts). It is consumed by V2 through @v2/iris-commentary-orchestration plus the V2AICommentary Unreal plugin.

The example below shows the complete call signature. Key parameters: determinismMode: 'off-rollback-only' is the hard contract flag; latencyBudgetMs sets the end-to-end deadline; fallbackMode: 'pre-recorded-bank' activates the pre-recorded fallback when the budget is exceeded; rightsContext carries the NIL/likeness metadata for rights gates.

typescript
import { createMatchCommentaryStream } from '@iris/conversation-orchestration';

const stream = createMatchCommentaryStream({
  matchId: 'match_abc123',
  commentators: [
    'calliope-v2-aria-voss-play-by-play',
    'calliope-v2-marcus-knox-color',
  ], // @calliope/persona-live ids
  ruleset: 'wwe', // cross-ref @shakti/fighting-ruleset-bridge
  determinismMode: 'off-rollback-only', // hard contract: never feeds simulation
  latencyBudgetMs: 800, // end-to-end cap from KO trigger to playable audio
  fallbackMode: 'pre-recorded-bank', // when latency exceeded
  rightsContext: { fighters: ['ryu', 'ken'], venue: 'metro-city-arena' },
});

stream.on('cue', (cue) => {
  // cue.kind: 'pre-match' | 'mid-match' | 'ko' | 'finisher' | 'reversal' | 'comeback' | 'post-match'
});

16.1 Determinism Guarantees#

The fundamental safety property is that commentary outputs are gameplay-inert: they are audio + subtitle only and never feed simulation state. Every emitted cue is an audio/subtitle artifact (an audio voice handle plus a subtitle string) — there is no field a cue can write that the rollback engine reads back. Because outputs don't influence the deterministic combat sim, the call itself can be asynchronous and non-deterministic without breaking rollback.

  1. No call from inside the rollback bubble. Commentary calls originate from V2's V2/services/ adapter layer, never from V2Combat, V2Gameplay, V2Input, or V2Netcode. Iris refuses calls tagged from-rollback-frame=true.
  2. No output mutates simulation state. Commentary tokens are audio / subtitle outputs only; they never feed game state, AI Director hints, balance counters, or any input the rollback engine consumes.
  3. Replay reproducibility via record-and-replay cache. The LLM call is non-deterministic, so a seed alone cannot regenerate the same line. The cache stores the specific output of the live call, keyed by (matchId, cueId, cueTriggerFrame, branchId) — a record-and-replay pattern. Each fresh replay-takeover from a mid-match save state mints a new branchId; re-playing the same takeover branch hits the cache.
  4. Per-peer cue distribution in 1v1 rollback matches. Each peer's V2/services/ adapter independently calls Iris; commentary is local-audio output only, so divergence between peers is acceptable (Invariant #2). Tournament broadcasts and spectator surfaces receive one canonical stream from the broadcaster's adapter (or the host peer's, absent a broadcaster).
  5. Latency budget with deterministic fallback. KO-trigger commentary has an 800 ms end-to-end budget (IRIS_MATCH_COMMENTARY_DEFAULT_LATENCY_BUDGET_MS = 800): ~420 ms Iris LLM round trip, ~240 ms persona TTS render, ~100 ms Psyche lipsync/expression render, ~40 ms safety margin. On budget overrun the contract emits a latency-budget-exceeded cue from the pre-recorded bank. Unlike the live record-and-replay cache (Invariant #3), the fallback line is fully deterministic so every peer and every replay selects the identical line: it is chosen by selectFallbackLine(buildIrisMatchCommentaryFallbackKey( …)) from a key whose shape is IRIS_MATCH_COMMENTARY_FALLBACK_KEY_SHAPE = '(cueKind,ruleset,commentatorId,seed)'. The IrisMatchCommentaryFallbackKey carries exactly those four fields — cueKind, ruleset, commentatorId, seed — and stringifyIrisMatchCommentaryFallbackKey produces the stable (cueKind,ruleset,commentatorId,seed) digest used to index the bank, so the pre-recorded fallback never desyncs peers or replays.

16.2 Cue Taxonomy#

Each cue type has its own latency budget that reflects how time-sensitive the associated game event is. Pre-match cues have generous 5-second budgets because they can be pre-baked during the loading screen. KO and reversal cues have tight 600–800 ms budgets because they must play while the game moment is still fresh. The finisher cue gets 1,200 ms because fatality/critical-art sequences have their own animation time that absorbs the extra latency.

Cue Trigger Latency budget
pre-match.intro Match-load fade-in 5,000 ms (pre-bake OK)
pre-match.tale Mid-load tale about the rivalry / venue 5,000 ms (pre-bake OK)
round.start Round begin 800 ms
combo.notable Player lands a notable combo 800 ms
reversal Counter-hit / parry / Drive Impact / Soul Charge / Reversal 600 ms
near-ko Defender HP < 10% 800 ms
ko KO event 600 ms
finisher Fatality / Critical Art / Rage Art / Critical Edge / Blazin' 1,200 ms
comeback Player overcomes a 50%+ HP deficit 800 ms
pre-match.tournament Tournament context line 5,000 ms (pre-bake OK)
post-match.recap Match-end recap pre-replay 1,500 ms

16.3 Per-Commentator Persona Binding and Gates#

Each commentator is not a generic TTS voice — it is a named AI artist with a distinct persona, vocal style, and rights profile. This section documents the rendering pipeline from LLM output to final audio, and the safety gates that run before any cue is emitted.

Each commentator binds to a @calliope/persona-live AI artist. The pipeline is: V2 cue trigger → @iris/conversation-orchestration (LLM call, off-rollback) → @calliope/persona-live persona transform → @iris/voice TTS → @psyche/avatar-lipsync + @psyche/avatar-expressions@euterpe/master mix ducking → V2 V2Audio MetaSounds graph.

Each cue passes rights + safety gates before emission — NIL/likeness clearance, originality checking, harm checking, regional tone filtering, and EU AI Act conformity. Several gate packages are planned, not yet on disk; specific package assignments are tracked in the V2 dependency backlog. Failed gates fall through to the pre-recorded bank with a logged reason code.

Cross-references to @themis/*, @kuanyin/*, @nous/safety, @calliope/persona-live, @v2/*, etc. describe planned cross-domain contracts owned by other domains and the V2 sister-monorepo; their existence and exact names are governed by those domains' own docs and backlogs, not this file.

16.4 V2 Bridge Surfaces (planned / cross-domain)#

The following V2-facing surfaces are described in the V2 architecture and dependency docs and are owned jointly with the V2 sister monorepo:

  • @iris/concordia-assistant (libs/iris/concordia-assistant, on disk) — Iris source of truth for appellant / arbiter dialogue scaffolding in Concordia-style dispute flows; consumed by V2 through @v2/concordia-substrate.
  • @iris/accessibility accessibility-bridge profile — consumed by V2 through @v2/iris-accessibility.
  • @iris/voice real-time translation routing — consumed by V2 through @v2/iris-realtime-translation for spectator chat, commentary localization, broadcast overlays, and companion second-screen feeds; presentation-only and off rollback.

These bridge contracts depend on packages owned by other domains; treat their naming and status as governed by the V2 and partner-domain docs.


17. V2 Accessibility Bridge Contract (V2 Consumer)#

The V2 fighting-game project consumes Iris for player accessibility across its Unreal main client and its companion surfaces. This V2 Accessibility Bridge Contract is owned by @iris/accessibility (libs/iris/accessibility/src/index.ts) and adapted into V2 by @v2/iris-accessibility (apps/v2/iris-accessibility/src/iris-accessibility.ts). Like the commentary contract in §16, every output is presentation / certification only: the surface sets mayInfluenceRollback: false and cannot change deterministic match-simulation state.

@iris/accessibility exports buildIrisV2AccessibilityBridge, the bridge id IRIS_V2_ACCESSIBILITY_BRIDGE_ID, and the capability vocabulary (caption-streaming, dyslexia-typography, cognitive-load-reduction, screen-reader-bridge, native-ue-accessibility-hooks). From a IrisV2AccessibilityProfileInput it derives:

  • Caption streaming. Iris does not yet own a live caption engine end to end, so the bridge names @psyche/caption-streaming as its real-time caption provider (the captionProviderPackageName field). V2 reuses the same Psyche engine that backs @v2/psyche-caption-streaming (see Psyche §19.2), keeping a single caption pipeline behind both the spectator/HUD path and the accessibility path.
  • Dyslexia-friendly typography. IrisV2DyslexiaTypographyTokens ships a dyslexia-safe font stack with letterSpacingEm: 0, generous word spacing and line height, a minimum body font size, and a measure cap — and asserts preservesButtonLabelFit so the typography change never clips fight-UI labels.
  • Cognitive assistive UI. IrisV2CognitiveLoadUiPolicy drives a reduced-cognitive-load mode (simplified language, persistent tutorial hints, step-by-step prompts, reduced-distraction chrome, reduced motion) while guaranteeing hidesCriticalActions: false — the cognitive assistive UI never removes a control the player needs to fight.
  • Screen-reader bridge. IrisV2ScreenReaderBridgePolicy defines the screen-reader bridge: a live-region policy of polite-status-assertive-critical, mandatory descriptions for every focusable widget, and suppression of dramatic color-only text so platform screen readers receive clean semantics.

@v2/iris-accessibility wraps that bridge through buildV2IrisAccessibilitySurface and surfaces explicit V2 control flags (controlsCaptionStreaming, controlsDyslexiaCognitiveAssistiveUi, controlsScreenReaderBridge, companionAndMainClientBridge, nativeUeAccessibilityHooks). It composes the Psyche caption engine via createAccessibilityCaptionEngine, emits the v2.accessibility.caption-stream.ready topic, and gates release on accessibility certification (certGateBlocksRelease: true). The rollback policy string is off-rollback-accessibility-ui-only, and the surface carries mayInfluenceRollback: false. The contract is validated by V2/ue/Tools/check-v2-iris-accessibility.py.


18. V2 Mobile Companion App (V2 Consumer)#

V2's second-screen companion is implemented as the React Native surface apps/oshun/mobile/v2/ (companionAppModel.ts, V2CompanionApp.tsx, V2CompanionLaunchTile.tsx, route app/v2.tsx). Its agent layer is the mobile-safe built-in catalog @iris/agents (see §5.5), which the companion imports to resolve frame-data and appeal-help agents.

buildV2CompanionModel assembles the companion from the shared Oshun client packages (@oshun/shell-core, @oshun/auth-client, @oshun/concordia-integration, @oshun/trust-safety) plus @sophia/client for local research and @iris/agents for the agent catalog. It calls resolveIrisAgentsLaunchReadiness to confirm the agent package is wired and selectIrisAgentForIntent to pick the frame-data-query agent for the "Open frame-data codex" action. The companion is purely a client surface; it never touches the rollback simulation. The binding is validated by V2/ue/Tools/check-v2-mobile-companion.py, whose Iris-facing checks require that apps/oshun/mobile/v2/ and @iris/agents are both named in this specification.


19. Acceptance Criteria#

These criteria define the minimum bar for a change to be considered complete and correct for the Iris domain. They are written to catch the most common failure modes: type misalignment, hardcoded config, storage claims that outrun implementation, and documentation that drifts from code.

A change to the Iris domain satisfies this specification when:

  1. Type fidelity — new or changed domain objects are defined in @iris/types with branded IDs and (for string unions) a paired Zod …Schema; co-located *.test.ts files cover the new types.
  2. Enum discipline — enum values added in code are reflected here; the four-tier MemoryTier model is preserved unless the enum itself changes.
  3. API contract — new @iris/api routes apply a rateLimiter preset, validate input with @hono/zod-validator, and surface errors through the errorHandler; the GraphQL schema stays consistent with the REST routes.
  4. State-machine soundness — changes to conversation-core keep the DialogueStateType / DialogueEvent transition table total (every non-terminal state handles ERROR and TERMINATE).
  5. Persistence honesty — claims about storage match reality: the Prisma schema has three models; the API services use in-memory Maps with DurableJsonStateStore JSON-file durability.
  6. Event transport honesty — event-transport descriptions remain Redis-backed (@oshun/event-bus); no Kafka claims.
  7. Configuration accuracy — new configuration keys are added to core/config/schemas.ts and read in loader.ts, and documented in §13.2 with their real variable names.
  8. No fabrication — every entity, endpoint, event, and count in the docs is traceable to source; planned-but-absent items are labelled (planned).