This file separates:
- Current runtime architecture (what is wired in
main.pytoday) - Target-state architecture (modules that exist or are planned, but are not the default live path)
Current runtime is chat-first:
integration message -> AI tool loop -> integration.output -> output dispatcher.
- Protocol-based core (
core/protocols.py) with plugin implementations. - Event bus for decoupled communication (
core/bus.py). - File-first persistent state with SQLite indexes (
core/data/store.py). - AI interface is the main user interaction layer (
engine/interface.py). - Integrations are transport adapters, not business-logic owners.
| Protocol | Purpose |
|---|---|
EventBus |
Pub/sub between components |
MarketDataProvider |
Price/market retrieval |
InputAdapter |
External inbound messages |
OutputAdapter |
External outbound delivery |
LLMProvider |
LLM completions + tool calls |
AIAgent |
Analysis agents (orchestrator path) |
RiskRule |
Deterministic signal gating rules |
TaskHandler |
Scheduled task execution |
graph TB
subgraph Integrations
TG[Telegram]
DC[Discord]
end
subgraph Core
AI[AI Interface]
BUS[AsyncIOBus]
SCH[Scheduler]
OUT[OutputDispatcher]
REG[PluginRegistry]
STORE[Store Files + SQLite]
end
subgraph Tooling
BT[Built-in Tools]
PT[Plugin Tools]
TH[Task Handlers]
end
TG --> AI
DC --> AI
AI --> BT
AI --> PT
AI --> BUS
SCH --> TH
TH --> BUS
BUS --> OUT
OUT --> TG
OUT --> DC
AI --> STORE
SCH --> STORE
REG --> AI
REG --> SCH
StoreAsyncIOBusPluginRegistrySchedulerPortfolioTrackerAIInterfaceOutputDispatchersubscribed tointegration.outputaiohttpserver (server.py)
- Integrations:
telegram,discord - Market data providers:
yahoo_finance - LLM providers:
openai,anthropic,openrouter(if API keys exist) - Task handlers:
ai.run_promptcomparison.weeklynews.briefingnotifications.sendweb.searchbrowser.selenium(optional, loaded only whenselenium_browseris enabled)
Risk rules are loaded and registered, but risk-gating events are part of the target-state pipeline (see below).
engine/interface.py is the live conversation controller for Telegram and Discord.
confirm_tradeskip_tradeclose_positionuser_initiated_tradeget_portfolioget_pricelist_taskslist_task_handlerscreate_taskdelete_taskdelete_task_by_nameget_memoriesget_signalsrun_analysis
Plugins can add tool schemas and execution handlers dynamically via:
get_tools()call_tool(...)
Plugins can also inject runtime prompt guidance via optional hooks:
get_system_prompt_instructions()get_scheduled_prompt_instructions()get_prompt_instructions(context=...)
Current plugin tools include:
get_news(news plugin)web_search(web search plugin)open_browser/close_browser/list_saved_logins/run_selenium_code/get_browser_screenshot/get_page_code(optional selenium browser plugin)
For selenium login flows, run_selenium_code provides helper get_saved_login("<profile_id>").
get_browser_screenshot returns a base64 image payload in tool output (data URL form when complete; preview + truncated flag when cut by max_base64_chars).
When a complete base64_data_url is present, the AI interface feeds it back into the next model turn as an image content part.
- Multi-round tool calls in one assistant turn.
- Max rounds:
25. - If limit is reached, the loop injects an internal max-rounds message and asks for confirmation in a new user turn.
- Conversation messages persist in SQLite table
conversation_messages. - First message in a channel stores one merged user entry:
- onboarding directive
- initial user message block
- Subsequent turns store user text normally.
- Scheduler reads task JSON files from
~/.clawquant/tasks. - Due tasks are executed by handler name (
Task.handler). - Task history fields (
last_run_at,last_result,run_count) are updated per run.
plugins/task_handlers/ai_runner.py invokes the same central AI interface used by chat.
Scheduled run context order:
- system prompt
- last 10 messages from same channel
- task prompt (
params.prompt)
Result is published as integration.output and delivered through the same output dispatcher path as chat.
All outbound user-visible messages are published as integration.output events.
core/output_dispatcher.py routes delivery by:
- optional
adapterconstraint - optional
channel_id - adapter capability (
send_text)
This keeps integrations modular and transport-focused.
server.py currently exposes:
GET /healthPOST /eventsGET /events(SSE)GET /state/portfolioGET /state/portfolio/{portfolio_type}GET /state/tasksPOST /tasksDELETE /tasks/{task_id}GET /state/signalsGET /state/memoriesGET /state/plugins
POST /chat is not currently implemented.
events/YYYY-MM-DD.jsonlsignals/*.jsonpositions/ai/*.jsonpositions/human/*.jsonmemories/*.jsontasks/*.jsonmemos/*.md
market_datamemory_indexconversation_messages
The following modules and flows exist conceptually (and partly in code) but are not the default live runtime path today:
engine/orchestrator.pyas always-on subscriber for live input eventsrisk/engine.pyactive gating ofsignal.proposedevents- Full signal lifecycle chain in production (
signal.proposed->signal.approved/rejected->signal.delivered) - Auto-creation of recurring tasks from config (
scheduler.default_tasks,learning.comparison_schedule) - Simulator exposure through CLI/server with validated workflow coverage
- Additional integrations/providers shown in legacy examples (email/webhook/custom scraper/CoinGecko)