Claude Code · Internal Architecture

Kairos — Assistant Mode

A long-running autonomous agent that operates as a persistent assistant rather than an interactive REPL session. Schedule-driven, proactive, and always on.

καιρός — Greek for "the right moment"
🚩

Feature Flag System

Two-Layer Gating Mechanism
Build-time
feature('KAIROS') is a Bun bundler compile-time constant. When false, dead-code-elimination strips all guarded code from the binary.
import { feature } from 'bun:bundle'
Runtime
GrowthBook entitlement tengu_kairos checked via src/assistant/gate.js at startup. Can be bypassed with --assistant flag (Agent SDK daemon).
Sub-Features
KAIROS
Full assistant mode — parent flag for everything below
KAIROS_BRIEF
BriefTool (SendUserMessage) as primary output channel
KAIROS_CHANNELS
MCP channel notifications — Discord, Slack, SMS inbound
KAIROS_DREAM
/dream skill — distills daily logs into topic files nightly
KAIROS_PUSH_NOTIFICATION
Push notifications when user is away from terminal
KAIROS_GITHUB_WEBHOOKS
GitHub PR webhook subscriptions via SubscribePRTool

Activation Flow

src/main.tsx · lines ~1048–1089 & 2206
1
Initialize
Set kairosEnabled = false as default.
2
Agent SDK Daemon Check
If --assistant flag is passed, call markAssistantForced() to skip GrowthBook entitlement check entirely.
3
Mode & Trust Checks
If isAssistantMode() AND not a spawned teammate AND workspace trust accepted:
  kairosEnabled = isAssistantForced() || await isKairosEnabled()
4
If kairosEnabled
Force --brief on  ·  call setKairosActive(true)  ·  call initializeAssistantTeam()  ·  append assistant system prompt addendum
5
System Prompt Injection (line 2206)
if (feature('KAIROS') && kairosEnabled && assistantModule) {
  const addendum = assistantModule.getAssistantSystemPromptAddendum();
  appendSystemPrompt = appendSystemPrompt
    ? `${appendSystemPrompt}\n\n${addendum}`
    : addendum;
}
🗂

Global State

Runtime Boolean — kairosActive
src/bootstrap/state.ts
// Getter
export function getKairosActive(): boolean {
  return STATE.kairosActive
}
// Setter
export function setKairosActive(v: boolean): void {
  STATE.kairosActive = v
}

Global runtime flag. Default: false.

React State — kairosEnabled
src/state/AppStateStore.ts · line 116
// AppStateStore.ts
kairosEnabled: boolean
// default: false (line 483)

Computed React state that flows into the component tree. Also stored in headless state (line 2648) as single source of truth for downstream consumers.

⚙️

Runtime Behavior Changes

When kairosActive = true, the following behaviors activate:

📤 Primary Output

BriefTool (SendUserMessage) becomes the required output channel. Plain text responses are hidden from the user.

📓 Memory System

Switches from live MEMORY.md to append-only daily logs at logs/YYYY/MM/YYYY-MM-DD.md.

⏰ Cron Scheduler

Runs with assistantMode: true, enabling durable cron job behavior.

💭 /dream Skill

Nightly consolidation of daily logs into topic-specific files and MEMORY.md.

🔌 Bridge Worker

Worker type set to "claude_code_assistant". Web UI routes these into a dedicated session picker.

🤖 AgentTool

All subagent spawns forced async (fire-and-forget). Prevents cron catch-up from blocking user input.

🖥 Background Tasks

PowerShell/Bash background tasks auto-enable in assistant mode.

🔁 Session Continuity

--session-id / --continue flags available for bridge session resume.

🔧

KAIROS-Specific Tools

ToolGatePurpose
BriefTool SendUserMessage KAIROS KAIROS_BRIEF
+ tengu_kairos_brief GB
Primary user-facing output. Supports attachments. Two independent entitlement checks.
SendUserFileTool KAIROS exclusive Sends files to the user. Only available in full Kairos mode.
PushNotificationTool KAIROS KAIROS_PUSH_NOTIFICATION Push notifications when user is away from the terminal.
SubscribePRTool KAIROS_GITHUB_WEBHOOKS Subscribe to GitHub PR events via webhooks.
SleepTool PROACTIVE KAIROS Yields the REPL loop. Wakes on ticks or when commands are queued.
CronCreate / Delete / List AGENT_TRIGGERS
+ tengu_kairos_cron GB
Schedule prompts for future execution — one-shot or recurring. 5-min GrowthBook refresh.

BriefTool — Two-Gate System
isBriefEntitled()
Can this user opt in at all?
kairosActive is true
CLAUDE_CODE_BRIEF env set
GrowthBook tengu_kairos_brief
isBriefEnabled()
Is it active right now?
isBriefEntitled() = true
kairosActive OR user opted in
GrowthBook still returns true
GrowthBook refresh window: 5 minutes (KAIROS_BRIEF_REFRESH_MS). Flipping tengu_kairos_brief off mid-session takes effect on the next refresh. When kairosActive is true, the user opt-in requirement is bypassed.

AgentTool — Async Forcing
assistantForceAsync = feature('KAIROS') ? appState.kairosEnabled : false

When Kairos is active, all subagent spawns are forced async via <task-notification> re-entry. Without this, a daemon's input queue backs up and the first overdue cron catch-up spawns N serial subagent turns, blocking all user input.

💬

KAIROS-Related Commands

src/commands.ts · lines 63–101
CommandGatePurpose
/proactive PROACTIVE KAIROS Proactive agent features
/brief KAIROS KAIROS_BRIEF Toggle brief-only output mode
/assistant KAIROS only Attach REPL as read-only viewer to a running session
/subscribe-pr KAIROS_GITHUB_WEBHOOKS GitHub PR webhook subscriptions
/loop isKairosCronEnabled() Schedule recurring cron tasks
CLI Subcommand — src/main.tsx:4334
if (feature('KAIROS')) {
  program.command('assistant [sessionId]')
    .description('Attach the REPL as a client to a running bridge session...')
}
🔔

Proactive Agent Ticks

src/cli/print.ts · lines 361–362, 2475–2479
Tick Injection Conditions
  • proactiveModule.isProactiveActive() is true
  • Session is not paused
  • Command queue is empty

A throttle mechanism prevents rapid successive ticks.

Build Artifact: src/proactive/index.js
  • isProactiveActive()
  • isProactivePaused()
  • activateProactive()
  • deactivateProactive()

Module conditionally loaded: feature('PROACTIVE') || feature('KAIROS')

👁

Viewer Mode — claude assistant

The CLI subcommand claude assistant [sessionId] attaches the REPL as a read-only client to a running assistant session.

🔌 WebSocket Connection

Connects to the running assistant bridge session in real time.

📜 Lazy History Loading

Paginated session event fetch via sessionHistory.ts using anchor_to_latest and before_id cursors.

📡 Real-Time Streaming

Live event streaming for monitoring the running session.

✉️ Send Messages

Can inject messages into the remote session despite being "read-only".

src/assistant/sessionHistory.ts exports: createHistoryAuthCtx()  ·  fetchLatestEvents()  ·  fetchOlderEvents()
src/hooks/useAssistantHistory.ts — React hook wrapping sessionHistory.ts with scroll-anchored lazy-loading, fill-viewport chaining (up to 10 pages on mount), and sentinel messages for virtual scroll.
📁

Daily Log Memory

src/memdir/memdir.ts · line 432
TEAMMEM (superseded)

Shared live MEMORY.md index maintained across a team. Incompatible with KAIROS. Kairos takes precedence when both would activate.

KAIROS Daily Log (active)

Append-only per-day log files at logs/YYYY/MM/YYYY-MM-DD.md. Nightly consolidation via /dream produces MEMORY.md + topic files.

Cache & Date Rollover

The prompt cache prefix is keyed on systemPromptSection('memory') and is not invalidated on date rollover. The model derives the current date from a date_change attachment injected at midnight.

if (feature('KAIROS') && autoEnabled && getKairosActive()) {
  // KAIROS daily-log mode takes precedence over TEAMMEM
}
💭

Auto-Dream Consolidation Service

src/services/autoDream/  ·  GrowthBook: tengu_onyx_plover_enabled

A background service that periodically fires /dream to consolidate daily logs into MEMORY.md and topic-specific files.

Gate Order — cheapest check first
1
Time Gate
minHours must have passed since last consolidation (from GrowthBook tengu_onyx_plover)
2
Session Gate
Minimum number of transcripts (minSessions) must have accumulated
3
Lock Acquisition
File-based mutex via consolidationLock.ts — prevents concurrent consolidation runs
FileRole
autoDream.tsOrchestrator — checks gates, acquires lock, forks the /dream agent
config.tsisAutoDreamEnabled() — GrowthBook gate tengu_onyx_plover_enabled
consolidationLock.tsFile-based mutex — readLastConsolidatedAt() / tryAcquireConsolidationLock() / rollbackConsolidationLock()
consolidationPrompt.tsbuildConsolidationPrompt() — generates the /dream skill prompt
Scheduler re-checks every 10 minutes (SESSION_SCAN_INTERVAL_MS) to avoid spinning when the time gate passes but the session gate is still blocking. Task progress is tracked via DreamTask.ts and shown in DreamDetailDialog.tsx.
📡

Channel Notification Architecture

KAIROS_CHANNELS MCP-based inbound messages from Discord · Slack · SMS · iMessage · Telegram
Inbound Message Flow
📱
External Platform
Discord / Slack / SMS
🔌
MCP Server
notifications/claude/channel
📦
Wrap & Queue
<channel source=…> XML
😴
SleepTool Wakes
within 1 second
🤖
Model Decides
channel tool / Brief / both
🛡

Multi-Layer Gate — gateChannelServer()

src/services/mcp/channelNotification.ts
1
Capability Check
MCP server must advertise the channel capability
2
GrowthBook tengu_harbor
Master on/off switch for all channel notifications
3
OAuth Check
Channels require OAuth authentication — API key users are always blocked
4
Org Policy
Managed orgs must have channelsEnabled: true in managed settings. KAIROS_CHANNELS is external: true, so org settings override the ledger.
5
--channels Session Flag
User must start the session with channels explicitly enabled
6
Allowlist — tengu_harbor_ledger
Server name must appear in the GrowthBook-managed approved channels list
7
Marketplace Verification
Prevents untrusted plugins from bypassing trust boundaries via capability claims
🔑

Channel Permission Relay

src/services/mcp/channelPermissions.ts  ·  GrowthBook: tengu_harbor_permissions (default: off)
Approval ID Format

5 lowercase letters from 25-char alphabet (a–z minus l). ~9.8M space. Blocklist-filtered for inappropriate words. Designed for phone-keyboard entry — no mode switching.

// Reply regex (server-side)
/^\s*(y|yes|n|no)\s+([a-km-z]{5})\s*$/i
Permission Flow
  • Tool use triggers permission request
  • CC sends structured prompt via CHANNEL_PERMISSION_REQUEST_METHOD
  • Channel server formats for platform (e.g. iMessage, Telegram)
  • User replies with yes/no + ID
  • Server emits structured event (not text matching)
Trust Boundary Warning: The allowlist (tengu_harbor_ledger) is the trust boundary, not the terminal. A compromised channel server that holds an allowlist entry can fabricate permission approvals for its own requests.
📊

Analytics Integration

Event Metadata

kairosActive: true flag appended to all analytics event payloads.

src/services/analytics/metadata.ts
Datadog Dimension

is_assistant_mode: true dimension in Datadog metrics. kairosActive in dimensional metrics list.

src/services/analytics/datadog.ts
Activation Path

getAssistantActivationPath() records whether session was activated via --assistant flag or GrowthBook entitlement.

src/assistant/index.js (build artifact)
📂

Key File Locations

Core
FileRole
src/main.tsxKAIROS initialization, activation flow, system prompt injection
src/bootstrap/state.tskairosActive global state, getter/setter
src/state/AppStateStore.tskairosEnabled React state (line 116)
src/commands.tsKAIROS-related slash commands
src/tools.tsKAIROS-specific tool registration
Assistant / Viewer Mode
FileRole
src/assistant/sessionHistory.tsViewer mode session history fetching
src/assistant/index.jsbuild artifactisAssistantMode, initializeAssistantTeam, getAssistantSystemPromptAddendum, getAssistantActivationPath
src/assistant/gate.jsbuild artifactisKairosEnabled() GrowthBook entitlement gate
src/assistant/sessionDiscovery.jsbuild artifact — discovers running assistant sessions on the host
src/assistant/AssistantSessionChooser.jsbuild artifact — session picker UI (used by src/dialogLaunchers.tsx)
src/bridge/bridgeMain.tsSession ID / continue flags, bridge worker setup
src/bridge/initReplBridge.tsBridge initialization; sets workerType = 'claude_code_assistant'
src/hooks/useReplBridge.tsxREPL bridge integration with KAIROS
src/hooks/useAssistantHistory.tsScroll-anchored lazy-loading of viewer session history
Memory & Consolidation
FileRole
src/memdir/memdir.tsDaily-log memory system; KAIROS takes precedence over TEAMMEM
src/memdir/paths.tsAssistant mode path utilities
src/services/autoDream/autoDream.tsBackground consolidation orchestrator
src/services/autoDream/config.tsisAutoDreamEnabled() — GrowthBook tengu_onyx_plover_enabled
src/services/autoDream/consolidationLock.tsFile-based mutex for consolidation runs
src/services/autoDream/consolidationPrompt.tsBuilds the /dream skill prompt
src/tasks/DreamTask/DreamTask.tsTask tracking for /dream runs
Channel Notifications
FileRole
src/services/mcp/channelNotification.tsCore handler — gateChannelServer(), wrapChannelMessage()
src/services/mcp/channelPermissions.tsPermission relay over channels; approval ID generation
src/services/mcp/channelAllowlist.tstengu_harbor gate; approved channels ledger
src/services/mcp/useManageMCPConnections.tsChannel-enabled MCP lifecycle management
src/components/LogoV2/ChannelsNotice.tsxStartup UI for --channels flag
Tools
FileRole
src/tools/BriefTool/BriefTool.tsxBrief tool — isBriefEntitled() / isBriefEnabled() two-gate system
src/tools/BriefTool/attachments.tsShared attachment logic (BriefTool + SendUserFile)
src/tools/SendUserFileToolFile sending — KAIROS exclusive
src/tools/ScheduleCronTool/prompt.tsisKairosCronEnabled() export
Scheduling
FileRole
src/hooks/useScheduledTasks.tsScheduled task runner; assistantMode param changes behavior
src/utils/cronScheduler.tsCore cron engine; assistantMode path
src/utils/cronJitterConfig.tsReads tengu_kairos_cron_config / tengu_kairos_cron_durable from GrowthBook
Proactive / Misc
FileRole
src/cli/print.tsInjects proactive ticks into REPL loop when Kairos active
src/proactive/index.jsbuild artifact — proactive agent activation/deactivation
src/services/analytics/metadata.tskairosActive analytics flag
src/services/analytics/datadog.tskairosActive Datadog dimension
src/services/compact/compact.tsConditionally loads session transcript module when KAIROS
src/components/StatusLine.tsxStatus line hides when KAIROS active
src/skills/bundled/index.ts/dream and /loop skill registration