Architecture Overview
OpenAlice is organized in four layers. Each layer has a clear responsibility and communicates with adjacent layers through well-defined interfaces.
┌─────────────────────────────────────────────────────────┐
│ Providers Claude Agent SDK · Vercel AI SDK │
├─────────────────────────────────────────────────────────┤
│ Core AgentCenter · ToolCenter │
│ ConnectorCenter · EventLog │
│ SessionStore · Compaction │
├─────────────────────────────────────────────────────────┤
│ Domain Trading · Market Data · Analysis │
│ News · Brain · Thinking · Browser │
├─────────────────────────────────────────────────────────┤
│ Interfaces Web UI · Telegram · MCP Server │
│ Tasks Cron Engine · Heartbeat │
└─────────────────────────────────────────────────────────┘
Providers
Two interchangeable AI backends, selectable at runtime:
- Claude Agent SDK — Uses
@anthropic-ai/claude-agent-sdk. Supports Claude Pro/Max OAuth login (via Claude Code CLI) or direct API key. Tools are delivered via an in-process MCP server. - Vercel AI SDK — Direct API calls to Anthropic, OpenAI, or Google. Tools are delivered via Vercel's native tool system.
The GenerateRouter reads ai-provider.json on each call and resolves to the active backend. Both providers implement the same interface:
ask(prompt)— Stateless one-shot promptgenerate(entries, prompt, opts)— Streaming generation with session history, yieldingProviderEvent(tool_use, tool_result, text, done)
You can switch providers at runtime via the Web UI or by editing the config file. Per-channel model overrides are also supported through sub-channels.
Core
AgentCenter
The top-level orchestration center. All AI interactions flow through AgentCenter, which manages the full pipeline:
- Append user message to session
- Resolve provider (may be overridden per-request)
- Compact session if context window is getting full
- Read active session window
- Delegate to provider for streaming generation
- Process provider events (log tool calls, extract media, strip images)
- Persist intermediate messages and final response to session
AgentCenter exposes two methods:
ask(prompt)— Stateless, no sessionaskWithSession(prompt, session, opts)— Full pipeline with history
ToolCenter
A centralized tool registry. Domain modules register their tools once during bootstrap. Consumers pull tools in the format they need:
getVercelTools()— For the Vercel AI SDK providergetMcpTools()— For the MCP server (used by Claude Agent SDK)
Tools can be disabled via data/config/tools.json or per-channel via sub-channel config. The disable list is read on each call, so changes take effect immediately.
ConnectorCenter
Manages outbound message delivery. Single-tenant, multi-channel design — one user, potentially reachable via multiple connectors (Web, Telegram, MCP Ask).
ConnectorCenter tracks which channel you last interacted through. When the heartbeat or a cron job needs to send you a message, it goes to that channel automatically. If no interaction has happened yet, it falls back to the first registered connector.
EventLog
A persistent append-only JSONL event bus with an in-memory ring buffer (500 entries). Every significant event — trade submissions, heartbeat results, cron fires, errors — flows through here.
- Dual-write: every append goes to disk and memory simultaneously
- Subscriptions: listeners can subscribe to all events or filter by type
- Recovery: on startup, the log file is read to restore the sequence counter and populate the buffer
SessionStore
JSONL-based conversation persistence. Each session is a file in data/sessions/. The format is compatible with Claude Code's session format.
Sessions support compaction — when the context window approaches its limit, AgentCenter summarizes older messages into a compact preamble, preserving the most recent exchanges in full.
Domain
Business logic modules, each owning its state and persistence. The tool/ layer is a thin bridge that registers domain capabilities as AI tools in ToolCenter.
Trading
The largest domain module, centered on the Unified Trading Account (UTA). Each UTA bundles:
- A broker connection (
IBroker) — abstract interface implemented by CCXT, Alpaca, and IBKR - A git-like operation history (
TradingGit) — stage, commit, push workflow - A guard pipeline — pre-execution safety checks
- A snapshot scheduler — periodic account state capture
The AccountManager owns the full UTA lifecycle: init, reconnect, enable/disable, remove. AI interacts with UTAs exclusively — brokers are internal implementation details.
See Unified Trading Account for the design rationale, Trading as Git for the workflow, and Accounts & Brokers for configuration.
Market Data
Structured data layer with two backends:
- TypeBB (default) — TypeScript-native OpenBB engine running in-process. No external sidecar needed.
- OpenBB API — Remote HTTP API if you prefer a separate process.
Covers equity, crypto, currency, commodity, and macro data with unified clients per asset class.
Analysis
Technical indicator calculator with an Excel-like formula syntax. Supports SMA, EMA, RSI, Bollinger Bands, MACD, ATR, and more. See Technical Analysis.
News
Background RSS collector with configurable feeds and a persistent JSONL archive. Three search tools follow the Unix philosophy: globNews (find by title), grepNews (search content), readNews (read full article).
Brain
Alice's persistent cognitive state. A frontal lobe stores working memory across conversations. Emotion tracking logs sentiment shifts with rationale. Both are versioned as commits with 8-char hashes. See Brain & Persona.
Interfaces & Tasks
Web UI
Local chat interface built on Hono with real-time SSE streaming. Features portfolio dashboard, equity curve visualization, config management, and trading approval UI. Supports sub-channels with per-channel AI config overrides.
Telegram
Bot integration via grammY. Commands, inline keyboards, media support, and push notifications. Auth-gated via allowed chat ID whitelist.
MCP Server
Exposes Alice's tools via the Model Context Protocol. Used internally by the Claude Agent SDK provider and can also be consumed by external MCP clients.
Cron Engine
Event-driven scheduling with three types: at (one-shot), every (interval), cron (5-field expression). Fires events into EventLog; a listener picks them up and runs them through AgentCenter.
Heartbeat
Periodic health-check built on the cron engine. Uses a structured response protocol — Alice decides whether to message you or stay quiet.
Composition Root
Everything is wired together in main.ts:
- Load config
- Create EventLog and ToolCallLog
- Create ToolCenter
- Create AccountManager, initialize trading accounts
- Create Brain (restore from disk or new)
- Create market data clients (TypeBB or OpenBB API)
- Load symbol index
- Register all tools with ToolCenter
- Create AI providers (Vercel + Agent SDK)
- Create AgentCenter with GenerateRouter
- Create ConnectorCenter
- Start cron engine, heartbeat, snapshot scheduler, news collector
- Start plugins (MCP, Web, Telegram, MCP Ask)
The composition root is the only place that knows about all components. Each component is decoupled and only depends on its direct collaborators via interfaces.