Multi-surface application runtime for Elixir. One TEA module, four render targets.
Framework core (Phases 1-6): TEA architecture, full render pipeline, 16 first-class widget types (Raxol.UI.Registry), focus + W3C-style event capture/bubble, terminal compat (color downsampling, Unicode width, synchronized output), playground (42 demos / 8 categories), 7 braille-resolution charts, Hex packaging, mix raxol.new, session recording.
OTP differentiators: process-per-component crash isolation, hot code reload, LiveView bridge, SSH app serving, time-travel debugging (snapshot every update/2), distributed swarm (CRDTs, topology election, libcluster + Tailscale).
Adaptive UI + effects: 8-rule LayoutRecommender, TrendDetector, Nx auto-retrain, Lifecycle integration, 5 MCP tools. Animation hints (Phase 15): declarative view/1 metadata to every surface (animate/stagger/sequence), terminal frames server-side, LiveView CSS with prefers-reduced-motion, MCP JSON hints. BorderBeam effect (three-layer glow, 4 variants, terminal + LiveView + MCP).
MCP surface (Phases 8-13): extracted raxol_mcp (server/client/registry, stdio + SSE). Auto-derives tools from the widget tree (16 Component modules implement ToolProvider) with a focus/hover lens; @mcp_exclude opt-out. Full spec coverage (prompts, logging, completion, notifications, circuit breaker). Resources + ContextTree + StructuredScreenshot + model-projection diffs. Pipe-friendly test harness with functor-law property tests.
Agent framework: TEA-based agents, coordinator/worker teams, 7 harness gaps closed (compaction, hooks, permissions, MCP client, streams, LSP, SSE). AI cockpit with SSE streaming for 9 backends. Virtual File System (pure-functional in-memory VFS, REPL helpers, 7 agent actions).
Coding agent: three surfaces on one launch path (Raxol.Agent.Code.Launcher): mix raxol.code (interactive TUI, also served over SSH single-tenant via --authorized-keys or multi-tenant via --ssh-tenants), mix raxol.p (headless one-shot), and mix raxol.acp (ACP on stdio for editors). ALLOW/ASK/DENY approval on every mutating tool call, a durable per-session journal behind --continue/--resume/--replay//rewind, /share read-only transcript links, .mcp.json servers bridged into the toolset, four harness_* MCP tools, and LLM spend metered into the shared Raxol.Payments.Ledger with budgets that halt a running turn.
Agent memory + self-improving skills (hermes-agent pickup): pluggable Raxol.Agent.Memory (Store.Ets, ETS+DETS, BM25-lite + recency + tags), pre-turn recall injection, memory_remember/recall/forget. Self-improving skill loop: Curator on an idle gate plus an isolated post-turn reviewer (SelfImprove) that authors/patches/consolidates SKILL.md skills (agentskills.io format). The same background pass does post-turn memory auto-capture and refreshes a dialectic per-user UserModel (both in turn.ex), and feeds a full-text session_search index. Config via memory_provider/0 / skills_provider/0 / self_improve/0. Remaining: recall-MCP bridge, hub client, paid skills.
Video render target (hermes-agent pickup): one TEA module to MP4/WebM/GIF, server-side frames at a virtual Animation.Clock, themed HTML via TerminalBridge rasterized through headless Chrome (zero-dep + warm-pool ChromicPDF), FFmpeg-encoded, mix raxol.render.
Commerce rails: agent payments with wallets (env + 1Password), ledger-enforced spending limits, and transparent HTTP-402 auto-pay across five protocols (x402, MPP, Xochi, Permit2, Riddler). Xochi is the cross-chain default (tier fees 0.10-0.40%, quote -> sign -> execute -> poll). PXE-bridge settlement (Glass Cube, 6 privacy tiers), ERC-5564/6538 stealth (Xochi.Stealth), ZKSAR attestation (6 proof types) + trust-tier routing. Riddler solver wired (ADR-0005, 9 endpoints, fee policy + privacy premiums).
raxol_earn v0.2 (pre-alpha): first Elixir/OTP-native Virtuals Agent Commerce Protocol, v2 hook/event model on the deployed Base contracts (v1 memo model retired). JobSession state machine (:open -> :budget_set -> :funded -> :submitted -> :completed plus :rejected/:expired), on-chain writes via HookClient -> AgenticCommerceV3 through an injected ProviderAdapter (SCA sponsored UserOps / JSONRPC EOA with NonceServer / Mock), full ERC-4337 SCA wallet (Alchemy Modular Account v2), Seller stack (Backend.{InMemory, WebSocket} + Queue + Runtime), mix raxol_earn.bench. Graduates on the first live Base-mainnet offering.
Surfaces: raxol_telegram (bot, per-chat router, inline keyboards), raxol_speech (TTS + Whisper STT + 21 voice commands), raxol_watch (APNS/FCM push, glanceable summaries, tap-to-event). raxol_symphony (pre-alpha): OTP port of OpenAI Symphony, a tracker-driven coding-agent orchestrator with two runners (raxol_agent + codex), three workflow modes (default/graph/graph_parallel batch fan-out), six surfaces, workflow hot-reload, evidence framework. Release-packaged; graduates on the first live run + Hex publish.
The twelve published Hex packages track two version lines: the framework packages (raxol + raxol_core/raxol_terminal/raxol_agent/raxol_mcp/raxol_liveview/raxol_plugin/raxol_sensor) move in lockstep on the 2.7.x line, and the independent payment/surface packages (raxol_payments, raxol_speech, raxol_telegram, raxol_watch) have their own 0.x line. raxol_earn, raxol_symphony, raxol_gateway, raxol_cli, raxol_console, and raxol_agent_client_protocol stay pre-alpha and unpublished until they graduate. Exact versions live in each mix.exs and are enforced by scripts/check-lockstep-deps.sh; do not restate them here, where nothing validates them.
| Task | Description | Effort |
|---|---|---|
Graduate raxol_earn |
Live run on Base mainnet with one offering, then the first Hex release | Medium |
Graduate raxol_symphony |
Parallel dispatch + release packaging landed; remaining: a live run against a real repo (see the package RUNBOOK.md), then mix hex.publish |
Medium |
Distilled from a fast-follow gap analysis vs NousResearch/hermes-agent. Moat tags: RAILS = routes agent spend through the commerce rails · SURFACE = another projection of the one TEA module · CATCH-UP = table-stakes to stop losing users at the door. Guard: nothing here may compromise the single-module invariant or the frame budget.
P0: funnel & reach
| Item | What | Effort | Tag |
|---|---|---|---|
| Install funnel | flake.nix and the Burrito-packaged raxol binary (raxol_cli, with an npm wrapper in packages/raxol_cli/npm) landed. Remaining: publishing the binary, raxol doctor/setup/update, and the Windows PowerShell installer |
M | CATCH-UP |
| Gateway breadth | Built: the Gateway.Adapter behaviour is frozen, Telegram is ported behind it (Raxol.Telegram.GatewayAdapter), Discord and Email adapters ship in-gateway, and Gateway.Pipeline.Transcribe gives every adapter voice memos through raxol_speech STT. Remaining: the first Hex release of raxol_gateway |
M | SURFACE |
| Cron scheduler | DONE. Raxol.Agent.Schedule.parse/1 (relative / interval / 5-field cron / ISO) plus Raxol.Agent.Scheduler, one timer per job with DETS persistence and boot replay, the cronjob Action, and Scheduler.Delivery to a gateway target or an in-process callback |
M | SURFACE |
| Memory remainder | The UserModel + post-turn auto-capture already ship; finish the Provider.RecallMcp bridge, optionally back session_search with SQLite FTS5, and extract raxol_memory/raxol_skills |
S/M | RAILS-adjacent |
P1: differentiation
| Item | What | Effort | Tag |
|---|---|---|---|
| Desktop app | Tauri shell over the LiveView surface with a Burrito'd BEAM sidecar (zero new UI); defaults the harness to :openrouter for the attribution funnel |
L | SURFACE |
| Metered tool gateway | Creative-media actions (image/video/tts/transcribe) behind an axol-hosted service that answers HTTP 402; any 402-speaking agent auto-pays per call via x402/Xochi (the commerce wedge) |
M | RAILS |
| Paid skills market | agentskills.io-format serializer + hub pull client + tradeable skills (a SKILL.md bundle with an ACP offering, settled on Base) |
M | RAILS |
| Migration on-ramp | mix raxol.import --from hermes/openclaw: SOUL.md -> persona, memories -> Memory.Store, skills, allowlists -> PermissionHook |
S | CATCH-UP |
| Windows first-class | Tune the pure-Elixir driver + Windows CI + the PowerShell installer path | M | CATCH-UP |
| OpenRouter funnel | Run the #414 live smoke with a real key, confirm the openrouter.ai/apps?url=https://raxol.io listing, bump site copy to v2.6 / 14 packages |
S | Funnel |
P2: deliberate laggards (do when pulled, not pushed)
- FLAME elastic exec on Fly Machines (BEAM-native idle hibernation, replaces Modal/Daytona).
- More gateway adapters: Slack (Socket Mode), then WhatsApp / Signal on demand.
- i18n: wire the present
gettextthrough surface rendering, extract locale files. - Agent Client Protocol adapter: shipped.
bin/raxol-acp/mix raxol.acp/raxol acpserve the coding agent over ACP on stdio (Raxol.Agent.ClientProtocol.Serve+StdioAgent, the full toolset with every sensitive Action gated on asession/request_permissionround trip) for editors that spawn an agent. Distinct fromraxol_earn. - Expose the AST-checked REPL as an agent action for scripted single-turn tool pipelines. The checker is a mitigation, not a boundary (see
Raxol.REPL.Sandbox), so this needs a node that already opted into evaluation and holds no keys.
Do not build: trajectory/training tooling, Singularity HPC backend, a 300-model subscription portal (that is Hermes's business; ours is settlement), or a SOUL.md personality system beyond what the import tool needs.
Tracked in #940. The Hermes analysis above measures the agent against a personal assistant; this measures mix raxol.code against a coding agent, omp (31 tools, 60+ providers, 14 LSP ops, 28 DAP ops). Both comparisons are kept, because they pull in different directions and neither alone describes the product.
Shipped: AGENTS.md/CLAUDE.md discovery on all three surfaces, the hash-anchored edit format (read_file anchors every line, edit_file addresses ranges by anchor), actionable model-facing tool errors, parallel sub-agent fan-out under a supervisor, and the LSP tools (#943): Raxol.Agent.Actions.Lsp exposes lsp (diagnostics, symbols, definition, references, hover) plus a gated lsp_rename that applies the server's own textDocument/rename edits inside a blast-radius cap, both registered in Raxol.Agent.Code.App's default actions, and write_file/edit_file append the file's diagnostics to their own results.
| Item | What | Effort |
|---|---|---|
| File-move rename | Raxol.Agent.LSPContext.will_rename/3 speaks workspace/willRenameFiles and the client advertises the capability, but no tool calls it, so moving a file still breaks every reference to it (#932) |
S |
| Reach | web_search + fetch, so the agent can read outside the workspace (#933) |
M |
todo |
Session-scoped plan tracking that survives compaction (#934) | S |
| Routing | Model roles, fallback chains, credential rotation; the sub-agent fan-out is the first beneficiary and the cost ledger makes it measurable (#937) | M |
bash |
PTY and background jobs; today nothing over 30 seconds can run at all (#938) | M |
ask |
Structured mid-turn questions (#935) | S |
| Vision | Image content blocks on the Anthropic and OpenAI paths (#936) | S |
| Inherited config | Read Cursor/Cline/Copilot/Windsurf instruction files where they already sit (#939) | S |
Do not build: DAP/debugger control, structural ast_edit, persistent Python/JS eval cells, browser and desktop control, commit splitting, or read-write collab. Revisit only when pulled.
Make Raxol a selectable runtime in the Virtuals ACP Console (app.virtuals.io/acp/new), beside Hermes and OpenClaw, with web3 native to the runtime (native raxol_earn plus the payment rails) rather than a bolted-on skill. Design in ADR-0031. It is the inverse of the custom_console_agent offering that already generates deployment packages for the other two runtimes.
| Item | What | Effort | Status |
|---|---|---|---|
:raxol package target |
Generator emits a raxol-targeted soul.md/AGENTS.md/tasks.json/skills/; Console.Package parses it back (round-trip tested) |
S | DONE |
| Stage-3 seam | A scheduled task runs under the soul.md persona and delivers to a gateway channel (Fire.runner + Scheduler.Delivery.gateway), proven end-to-end |
S | DONE |
raxol_console loader |
DONE. RuntimeConfig + Scheduler.Wiring + Boot/Supervisor/Reconciler (persona-wired scheduler + idempotent job convergence) + gateway channel subtree (per-chat sessions run the persona handler; MCP/dynamic tools dispatch via ReAct) + Console.Bench.Adapter (native bench: boots the runtime, runs boot/prompt/task-dry-run checks) + Console.Application (container entrypoint: plan from config/env -> load package -> boot; no-op when unconfigured, self-starts outside :test). 27 tests |
M | DONE |
| Tool breadth to 40+ | DONE: dynamic-dispatch seam (Action.Dynamic) + Agent.McpBundle (default server set, fail-open, wraps each server's tools). raxol_console Boot loads the bundle and joins its tools into the chat handler's :actions (dispatched via ReAct). 25 built-ins + bundled filesystem/fetch/git/... -> ~50 callable tools |
S | Done |
| Native ACP registration | Scaffolded: Chain registry-address field + require_service_registry/1 fail-closed gate; JobApi.register_agent/2 optional callback (Mock impl); idempotent Seller.Registration.ensure_registered/3. Blocked on Virtuals: registry address, HTTP register endpoint, identity standard (ERC-8004/8183), and the on-chain HookClient.register_agent variant |
M | Scaffolded / partner-blocked |
| TEA app_module handler | Optional Handler.Lifecycle runtime mode for a stateful per-chat UI (issue #763) |
M | Deferred |
The load-bearing unknown is external: the Console's third-party runtime-registration and container contract is undocumented, escalated to Virtuals (~/Desktop/virtuals-console-runtime-questions.md).
One free, indexer-agnostic read layer over the chains we settle on, served as MCP tools and as agent Actions. Design in ADR-0033. Blockscout declined to index anything non-EVM without a funded per-chain agreement, and relicensed their MCP server and explorer in April and May 2026 (revocable, no redistribution, SaaS included), so forking is closed. Their hosted MCP is closing too: probing it on 2026-08-31 returned a free budget of 10 tool calls per session and notice that all requests require a PRO key from 2026-10-08. Consuming the public REST API carries no licence obligation and stays open today, which is the path taken, but the per-chain fallbacks are load-bearing rather than defensive. The package sits below raxol_payments because reads are more fundamental than payments, and that move dissolves the existing wart where ChainReader hand-rolls a second Req client purely to dodge a cycle. Three consumers: raxol's own settlement agents, a public free MCP server with the non-EVM coverage nobody else offers, and consolidation of the five competing RPC env conventions.
| Item | What | Effort | Status |
|---|---|---|---|
Raxol.MCP.Aggregator |
The one missing conversion direction: upstream MCP server -> Raxol.MCP.Registry tool defs, over the existing MCP.Client. Janitor lifecycle and admit/1 bounds copied from Code.McpLoader |
S | Planned |
| Package skeleton | raxol_web3 at 0.1.0, standalone on raxol_core + raxol_mcp + req; Backend behaviour (6 required + 8 optional callbacks, CAIP-2/10/19 refs, opaque cursors) + Stub in lib/; move ChainReader, Tron.Address, Pxe.Client, Payments.Poll down with shims; rate limiting reuses Raxol.Core.TokenBucket, and a Cache behaviour + ETS adapter is built here since Raxol.Agent.Cache is not reachable from this graph |
L | Planned |
| EVM backend | Blockscout REST v2 + Chainscout resolution (746 chains, keyless, includes 4663) + RPC fallback. Identifies honestly and treats a Cloudflare challenge as backend-unhealthy so the router fails over, rather than sending a browser User-Agent; per-chain health checks (base and polygon were 500ing) | M | Planned |
| Tron backend | TronGrid MCP (149 tools, keyless, verified live) and SQD Portal via mcp_proxy; TronScan secondary, pinned to a serialized policy since parallel calls on one session fail |
S | Planned |
| Solana backend | SQD Portal solana-mainnet + public RPC fallback. Requests per second binds long before monthly volume does |
S | Planned |
| Aztec backend | aztecscan keyless API, reusing Pxe.Client. Public state only; private state is architecturally unavailable |
S | Planned |
| Canton backend | ccscan MCP (13 tools, stateless) or Noves (MIT); Splice Scan client generated from the Apache-2.0 OpenAPI spec. Exercises party IDs and rounds, so it validates the optional half of the contract | M | Planned |
| RPC config consolidation | Collapse RPC_<NAME> / DERIVE_RPC_ / ORDER_RPC_ / XOCHI_ORDER_RPC_ / GATE_RPC_ onto one resolver; repoint derive_caps, capacity gating, checkpoints |
M | Planned |
A second survey pass (docs/proposals/web3-upstream-survey.md) moved Canton from blocked to ordinary adapter work and shrank Tron, because both Tron explorers run keyless MCP servers that were verified live. The real design constraint turned out to be at the wire level: of three upstream servers probed, one is stateful and concurrency-safe, one is stateful and fails every parallel call on a shared session, and one is stateless, and two frame SSE incompatibly. Concurrency policy is therefore declared per backend rather than assumed. The remaining risk is concentration, since SQD backs several chains at once and its parent was acquired in October 2025, so per-chain fallbacks must stay exercised rather than merely present.
RATE (Raxol Automated Testing Environment). Model: FFmpeg's FATE (end-to-end reference-hash suite over a distributed runner network) plus checkasm (a pure reference oracle that an optimized path must match byte-for-byte), adapted to Nix-pinned self-hosted runners spanning x86_64 and aarch64 (Linux + Darwin) over a Tailscale mesh. The flake is the bench: checks.<system>, packages.raxol-burrito-<triple>, and a NixOS runner config are all flake outputs, so every runner is reproducible and architecture is the only variable, not environment drift. Closes three current gaps: the termbox2 NIF is skipped in all CI today (SKIP_TERMBOX2_TESTS=true), there is no aarch64-linux tier, and the swarm/CRDT paths never run against a real multi-node cluster. All four layers are planned.
| Layer | What | FATE analogue |
|---|---|---|
| Multi-arch checks | Run the full suite with the termbox2 NIF actually built and exercised on x86_64-linux, aarch64-linux, and aarch64-darwin (plus the Windows pure-Elixir driver). Drop SKIP_TERMBOX2_TESTS on real hardware. |
breadth matrix |
| Oracle + golden render | IOTerminal (pure-Elixir reference) vs the termbox2 NIF, byte-exact for the same op stream; plus mix raxol.rate: a deterministic corpus of TEA apps -> ScreenBuffer/ANSI hash, references committed (--gen), compared per architecture. |
checkasm oracle + reference md5 |
| Real-cluster swarm | Declaratively deploy the BEAM app across the mesh over Tailscale; orchestrate partition and heal; assert CRDT (ORSet/LWWRegister) convergence and topology re-election across real nodes. |
(beyond FATE) |
| Burrito release matrix | Per-target self-contained binaries (aarch64/x86_64 Linux, Darwin, Windows) cross-compiled via zig; each smoke-tested on its actual silicon over the mesh before it is trusted. | reference run on real hardware |
Substrate: builds on the PR #441 flake. nix run / bin/raxol exposes both the interactive playground and a headless golden-render entrypoint (Raxol.Release.golden/0) reused as the per-arch smoke test.
Determinism discipline (the FATE rule, "flaky is deterministic, dig in"): render output must hash-stably. The virtual Animation.Clock is already frame-deterministic; the remaining guards are map-ordering leaks, locale-dependent Unicode width, and concurrent-render process ordering. A flaky golden hash is a real bug, not noise.
Supported now:
- Mock (fallback for the example agents and
raxolchat; the coding-agent surfaces auto-detect a real provider and error with a setup hint when none is configured): instant offline demo, no API key - Proton Lumo (
PROTON_UID=... PROTON_ACCESS_TOKEN=...): zero-access encrypted AI, full U2L encryption viaBackend.Lumo - Proton Lumo via lumo-tamer (
LUMO_TAMER_URL=http://localhost:3000): OpenAI-compatible proxy fallback - Kimi K2.5 (
KIMI_API_KEY=...): Moonshot AI, $0.60/M input, 256K context, named:kimiprovider - LLM7.io (
FREE_AI=true): free, OpenAI-compatible, no key needed, 40 req/min - Ollama (
OLLAMA_MODEL=...): free local inference, OpenAI-compatible - LM Studio (
:lm_studiobackend): local OpenAI-compatible server,http://localhost:1234by default - LongCat (
:longcatbackend): Meituan'sLongCat-2.0over the OpenAI-compatible path - Groq (
AI_API_KEY=... AI_BASE_URL=https://api.groq.com/openai): fast free tier - OpenAI (
AI_API_KEY=...): GPT-4o-mini and up - Anthropic (
ANTHROPIC_API_KEY=...): Claude Haiku/Sonnet/Opus - OpenRouter (
:openrouterharness, key viaExecutorConfigauth): OpenAI-compatible aggregator that sends app-attribution headers (HTTP-Referer, X-OpenRouter-Title, X-OpenRouter-Categories) so Raxol appears on openrouter.ai/rankings
- Multi-node cockpit (swarm coordination across physical terminals)
- Plugin marketplace
- VS Code extension for component previews
- SSH session multiplexing (tmux-like panes)
- Collaborative sessions (multi-user terminal sharing)
- Documentation site (widget gallery, tutorials, examples)
Want to help? See CONTRIBUTING.md.
- Minor (2.x.0): New features, framework additions
- Patch (2.0.x): Bug fixes, performance improvements
- Major (3.0.0): Breaking API changes, architectural shifts