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.
Feature Flag System
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'
tengu_kairos checked via src/assistant/gate.js at startup. Can be bypassed with --assistant flag (Agent SDK daemon).
Activation Flow
kairosEnabled = false as default.--assistant flag is passed, call markAssistantForced() to skip GrowthBook entitlement check entirely.isAssistantMode() AND not a spawned teammate AND workspace trust accepted:kairosEnabled = isAssistantForced() || await isKairosEnabled()kairosEnabled--brief on · call setKairosActive(true) · call initializeAssistantTeam() · append assistant system prompt addendum
if (feature('KAIROS') && kairosEnabled && assistantModule) {
const addendum = assistantModule.getAssistantSystemPromptAddendum();
appendSystemPrompt = appendSystemPrompt
? `${appendSystemPrompt}\n\n${addendum}`
: addendum;
}
Global State
kairosActive// Getter
export function getKairosActive(): boolean {
return STATE.kairosActive
}
// Setter
export function setKairosActive(v: boolean): void {
STATE.kairosActive = v
}
Global runtime flag. Default: false.
kairosEnabled// 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:
BriefTool (SendUserMessage) becomes the required output channel. Plain text responses are hidden from the user.
Switches from live MEMORY.md to append-only daily logs at logs/YYYY/MM/YYYY-MM-DD.md.
Runs with assistantMode: true, enabling durable cron job behavior.
Nightly consolidation of daily logs into topic-specific files and MEMORY.md.
Worker type set to "claude_code_assistant". Web UI routes these into a dedicated session picker.
All subagent spawns forced async (fire-and-forget). Prevents cron catch-up from blocking user input.
PowerShell/Bash background tasks auto-enable in assistant mode.
--session-id / --continue flags available for bridge session resume.
KAIROS-Specific Tools
| Tool | Gate | Purpose |
|---|---|---|
| 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. |
kairosActive is trueCLAUDE_CODE_BRIEF env settengu_kairos_briefkairosActive OR user opted inKAIROS_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.
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
| Command | Gate | Purpose |
|---|---|---|
/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 |
src/main.tsx:4334if (feature('KAIROS')) {
program.command('assistant [sessionId]')
.description('Attach the REPL as a client to a running bridge session...')
}
Proactive Agent Ticks
proactiveModule.isProactiveActive()is true- Session is not paused
- Command queue is empty
A throttle mechanism prevents rapid successive ticks.
src/proactive/index.jsisProactiveActive()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.
Connects to the running assistant bridge session in real time.
Paginated session event fetch via sessionHistory.ts using anchor_to_latest and before_id cursors.
Live event streaming for monitoring the running session.
Can inject messages into the remote session despite being "read-only".
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
Shared live MEMORY.md index maintained across a team. Incompatible with KAIROS. Kairos takes precedence when both would activate.
Append-only per-day log files at logs/YYYY/MM/YYYY-MM-DD.md. Nightly consolidation via /dream produces MEMORY.md + topic files.
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
tengu_onyx_plover_enabledA background service that periodically fires /dream to consolidate daily logs into MEMORY.md and topic-specific files.
minHours must have passed since last consolidation (from GrowthBook tengu_onyx_plover)minSessions) must have accumulatedconsolidationLock.ts — prevents concurrent consolidation runs| File | Role |
|---|---|
autoDream.ts | Orchestrator — checks gates, acquires lock, forks the /dream agent |
config.ts | isAutoDreamEnabled() — GrowthBook gate tengu_onyx_plover_enabled |
consolidationLock.ts | File-based mutex — readLastConsolidatedAt() / tryAcquireConsolidationLock() / rollbackConsolidationLock() |
consolidationPrompt.ts | buildConsolidationPrompt() — generates the /dream skill prompt |
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
Multi-Layer Gate — gateChannelServer()
tengu_harborchannelsEnabled: true in managed settings. KAIROS_CHANNELS is external: true, so org settings override the ledger.--channels Session Flagtengu_harbor_ledgerChannel Permission Relay
tengu_harbor_permissions (default: off)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
- 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)
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
kairosActive: true flag appended to all analytics event payloads.
is_assistant_mode: true dimension in Datadog metrics. kairosActive in dimensional metrics list.
getAssistantActivationPath() records whether session was activated via --assistant flag or GrowthBook entitlement.
Key File Locations
| File | Role |
|---|---|
src/main.tsx | KAIROS initialization, activation flow, system prompt injection |
src/bootstrap/state.ts | kairosActive global state, getter/setter |
src/state/AppStateStore.ts | kairosEnabled React state (line 116) |
src/commands.ts | KAIROS-related slash commands |
src/tools.ts | KAIROS-specific tool registration |
| File | Role |
|---|---|
src/assistant/sessionHistory.ts | Viewer mode session history fetching |
src/assistant/index.js | build artifact — isAssistantMode, initializeAssistantTeam, getAssistantSystemPromptAddendum, getAssistantActivationPath |
src/assistant/gate.js | build artifact — isKairosEnabled() GrowthBook entitlement gate |
src/assistant/sessionDiscovery.js | build artifact — discovers running assistant sessions on the host |
src/assistant/AssistantSessionChooser.js | build artifact — session picker UI (used by src/dialogLaunchers.tsx) |
src/bridge/bridgeMain.ts | Session ID / continue flags, bridge worker setup |
src/bridge/initReplBridge.ts | Bridge initialization; sets workerType = 'claude_code_assistant' |
src/hooks/useReplBridge.tsx | REPL bridge integration with KAIROS |
src/hooks/useAssistantHistory.ts | Scroll-anchored lazy-loading of viewer session history |
| File | Role |
|---|---|
src/memdir/memdir.ts | Daily-log memory system; KAIROS takes precedence over TEAMMEM |
src/memdir/paths.ts | Assistant mode path utilities |
src/services/autoDream/autoDream.ts | Background consolidation orchestrator |
src/services/autoDream/config.ts | isAutoDreamEnabled() — GrowthBook tengu_onyx_plover_enabled |
src/services/autoDream/consolidationLock.ts | File-based mutex for consolidation runs |
src/services/autoDream/consolidationPrompt.ts | Builds the /dream skill prompt |
src/tasks/DreamTask/DreamTask.ts | Task tracking for /dream runs |
| File | Role |
|---|---|
src/services/mcp/channelNotification.ts | Core handler — gateChannelServer(), wrapChannelMessage() |
src/services/mcp/channelPermissions.ts | Permission relay over channels; approval ID generation |
src/services/mcp/channelAllowlist.ts | tengu_harbor gate; approved channels ledger |
src/services/mcp/useManageMCPConnections.ts | Channel-enabled MCP lifecycle management |
src/components/LogoV2/ChannelsNotice.tsx | Startup UI for --channels flag |
| File | Role |
|---|---|
src/tools/BriefTool/BriefTool.tsx | Brief tool — isBriefEntitled() / isBriefEnabled() two-gate system |
src/tools/BriefTool/attachments.ts | Shared attachment logic (BriefTool + SendUserFile) |
src/tools/SendUserFileTool | File sending — KAIROS exclusive |
src/tools/ScheduleCronTool/prompt.ts | isKairosCronEnabled() export |
| File | Role |
|---|---|
src/hooks/useScheduledTasks.ts | Scheduled task runner; assistantMode param changes behavior |
src/utils/cronScheduler.ts | Core cron engine; assistantMode path |
src/utils/cronJitterConfig.ts | Reads tengu_kairos_cron_config / tengu_kairos_cron_durable from GrowthBook |
| File | Role |
|---|---|
src/cli/print.ts | Injects proactive ticks into REPL loop when Kairos active |
src/proactive/index.js | build artifact — proactive agent activation/deactivation |
src/services/analytics/metadata.ts | kairosActive analytics flag |
src/services/analytics/datadog.ts | kairosActive Datadog dimension |
src/services/compact/compact.ts | Conditionally loads session transcript module when KAIROS |
src/components/StatusLine.tsx | Status line hides when KAIROS active |
src/skills/bundled/index.ts | /dream and /loop skill registration |