AXIOM is a monochrome, browser-native orchestration console that turns an OpenRouter API key into a live agent mesh. The user enters a mission objective, an LLM orchestrator plans and dispatches tasks to specialized agents in parallel, and the whole execution is visualized in real time on a Canvas 2D scene with streaming tokens, event feed, and a markdown artifact modal.
- Anti-Bias Gate: Fresh Context critic + Jury Mode with majority vote
- Isolated draft-shard artifacts + deterministic merge node
- Amdahl telemetry + HUD chip
- Graph Shapes: Standard, Deep Research, Adversarial Review, Broad Sweep
- Expanded tests/docs + Playwright per-shape e2e
- OpenRouter
:freetier works end-to-end. Default agents now target verified free models (google/gemma-4-26b-a4b-it:free,z-ai/glm-5.2:free,nvidia/nemotron-3-super-120b-a12b:free,poolside/laguna-xs-2.1:free). No key charges in SIM or real mode. - BYOK key actually reaches the engine. The provider was previously built once from a non-existent
VITE_env value (always empty → 401). It now lazily reads the key you connect with (Vault →localStorage/sessionStorage/Stronghold) and is injected into the Web Worker (workers have nolocalStorage) viasetRuntimeKey/ensureProviderFor. - Failure-signal hardening (false-green audit):
- Critic
fallbackModelis free (poolside/laguna-xs-2.1:free) — a paid fallback would silently charge the user on model outage. Regression-guarded by a test. budgetAvailableno longer swallows a 401 as "ok": an invalid key surfaces a clearBUDGET ▸ API key rejected by OpenRouter (401)fault before the mission starts.- Empty/unknown model responses fail fast (
unavailable) instead of looping astransient.
- Critic
- Mobile layout fixed. The header overflowed ~67px on ≤390px viewports, clipping the primary
"Run Mission" CTA. The logo subtext now hides below
sm, clusters shrink (min-w-0), and the CTA collapses to "Run" on mobile — fully reachable, no horizontal scroll at 390×780. - Regression suite added.
tests/policies.test.ts(free-tier fallback + error classification) andtests/vault_budget.test.ts(invalid-key / exhausted / unreachable budget signals). Live e2e (e2e/live_free.spec.ts) runs a real mission against OpenRouter free models in a browser.
AXIOM running in a real browser (Chromium) against OpenRouter free models — idle mesh, mission dispatch, live agent activity, and the delivered artifact.
| Boot / idle mesh | Objective + graph-shape selector | Mission running | Delivered artifact |
|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
| Idle mesh | Objective dialog | Mission running | Artifact |
|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
Screenshots captured with
e2e/shots.spec.ts(pnpm run test:e2e --e2e/shots.spec.tsafterpnpm run dev). If a free-model run is rate-limited, re-run — the engine retries transients.
- Vite + React 19 + TypeScript 7 (strict)
- Tailwind v4 via
@tailwindcss/vite - State: Zustand, TanStack Query
- LLM: OpenRouter via Vercel AI SDK +
@openrouter/ai-sdk-provider - Animation:
motion/react, GSAP - Persistence: Dexie (IndexedDB)
- Markdown: react-markdown, remark-gfm, shiki
- Fonts: self-hosted via
@fontsource/space-grotesk,@fontsource/jetbrains-mono - Testing: Vitest, Playwright
- Desktop: Tauri 2 +
tauri-plugin-stronghold
pnpm install
pnpm run dev
pnpm run build
pnpm run lint
pnpm test
pnpm run test:e2eIf pnpm is unavailable or broken in your shell, use the Corepack fallback:
corepack enable
npx pnpm@latest install
npx pnpm@latest run devVITE_API_BASE— optional OpenRouter base URL. Defaults tohttps://openrouter.ai/api/v1.VITE_SEARCH_ENDPOINT— optional Wikipedia-compatible search endpoint forweb_search.- All network calls go to OpenRouter directly from the browser. For production, route through your own proxy and set
VITE_API_BASEto that proxy origin.
Deploy proxy/worker.ts to Cloudflare Workers:
cd proxy
npx wrangler deployThen set VITE_API_BASE to the worker origin. The proxy handles CORS, rate limiting, and unbuffered SSE streaming.
- The user supplies their own OpenRouter key via the Vault dialog.
- Keys are stored in
localStorageby default, orsessionStoragewhen “Session only” is checked. - In Tauri desktop builds, keys are stored via
tauri-plugin-strongholdinstead of web storage. - Keys are masked in the UI as
••••+last4and are never logged or sent anywhere except theAuthorizationheader. - AXIOM never persists mission artifacts with secrets; artifacts contain only model output.
AXIOM now treats missions as a production graph with typed primitives:
- NODE: an agent with a role, model, system prompt, declared
outputSchema,failurestate, and per-rolepolicy(retries, fallback model, on-fail behavior). Default schemas enforce structured JSON for researcher, analyst, writer, and critic. - EDGE: a routed dispatch from orchestrator to worker. Edges carry artifact references (
artifactId,summary) in planning context, never full transcripts. - STATE: durable mission state stored via Dexie
checkpointsafter every step and gate/policy event. Enables resume after reload or interruption. - ROUTER: deterministic orchestrator loop. Tracks route decisions, artifact refs, convergence, and step budgets. History contains references + summaries only.
- GATE:
final-gateruns every timefinalis emitted. Deterministic checks validate content, schema, and citations. An independent critique pass follows. FAIL routes back for repair up to 2 rounds; exhausted failures deliver withverified:false.
New additive bus events:
artifact-stored— emitted when an artifact is persisted.gate-start/gate-pass/gate-fail— final-gate lifecycle.policy-applied— per-node failure policy decision.convergence— emitted when research hits dry rounds or budget cap.approval-requested— emitted when delivery requires human approval.checkpoint-updated— emitted after every durable state write.resume-available— emitted on app load when interrupted missions can be resumed.
- Require approval before delivery — persisted toggle. Default ON for real missions, OFF in SIM mode. When enabled, gate PASS puts the mission into
awaiting-approval; the ApprovalDialog lets users Approve, Reject with feedback, or Abort.
- On app load, AXIOM scans checkpoints with status
running|paused|awaiting-approval|interruptedand surfaces a RESUME MISSION button in Header. - Resume restores history from artifact references + decisions, continues from
currentStep, and logsSYS ▸ resumed from step N. - RESET and completion clear/archive checkpoints. Abort marks
interrupted.
Pure TypeScript, zero React/DOM. Owns:
types.ts—BusEvent,AgentDef,Plan,MissionRecord,ArtifactRecord,CheckpointRecordbus.ts— typed event bus used as the only cross-layer seamvault.ts— key storage, masking, localStorage/sessionStorage/Stronghold helpers, budget guardopenrouter.ts—API_BASE, auth header factory,/keyand/modelsfetch helpersprotocol.ts— Zod schema for orchestrator JSON + repair-and-retry parseragents.ts—AGENT_DEFSregistry, model overrides, dynamic spawn, output schemas, policiesartifacts.ts— artifact schema, structured summary extraction, repair parser, artifact-stored event helpergates.ts—final-gatedeterministic checks, critique, repair rounds, verdict emissionpolicies.ts— per-role failure policy resolution andpolicy-appliedbus emissioncheckpoints.ts— durable mission checkpoint store with localStorage + memory fallbackstorage.ts— Dexie-backedArtifactStoreandCheckpointStoreorchestrator.ts— plan loop, parallel dispatch, artifact persistence, gate integration, convergence, budgetssimulator.ts— offline SIM mode exercising artifact store, gate, policy, convergence, checkpointsgraph.ts— node/edge data model + physics steptools.ts—web_searchandcode_exectool registry with Zod schemas
Canvas 2D scene, zero React imports, owns its requestAnimationFrame loop:
scene.ts— DPR handling, grid/dust/vignette, camera transformsnodes.ts— node birth, halo, selection brackets, radar sweep, done glyphedges.ts— draw-in edges, message particles with trails, delivery flashinput.ts— drag node, pan, zoom-to-cursor, click-select
React 19 components. Never call APIs directly; consume stores + bus:
App.tsx— layout shell, overlay mounts, motion wrapperscomponents/BootOverlay.tsx— GSAP boot timelinecomponents/Header.tsx— brand, status, metrics, controls, resume buttoncomponents/Roster.tsx— agent list / mobile Sheetcomponents/Feed.tsx— throttled event stream with gate/policy/convergence linescomponents/Stage.tsx— canvas host, rAF loop, bus bindingscomponents/DetailCard.tsx— selected node inspector + model picker + tool list + contract sectioncomponents/ArtifactModal.tsx— react-markdown + COPY + verification badgecomponents/HistoryDrawer.tsx— Dexie mission logcomponents/ObjectivePrompt.tsx— mission input dialogcomponents/GraphDrawer.tsx— inspectable routing decisions drawercomponents/ApprovalDialog.tsx— human approval / escalation dialoghooks/— useBus, useKeyInfo, useModels
Zustand stores:
mission.ts— status, objective, step/total, fault, current artifact id, verified flagmesh.ts— roster mirror, agent states, model overrides, tool listvault.ts— connected, masked key, balance, async connect/disconnectfeed.ts— 90-entry log with ~80ms throttled flush, gate/policy/convergence entriessettings.ts— speed 1|2|4, reduced motionui/stores/bus.ts— UI overlay state + bus→Zustand bridge
AXIOM agents can use built-in tools during streaming:
web_search— searches Wikipedia REST API for top 5 page results. Attached to RESEARCHER by default. Overridable viaVITE_SEARCH_ENDPOINT.code_exec— executes JavaScript in a sandboxed context with 2s timeout. Attached to ANALYST by default. Output is markeduntrusted.
Tools emit tool-call and tool-result bus events, which appear in the Feed and ping the node canvas.
src/engine/cost.tscaches model pricing and records per-call token usage.- Mission-level and per-node cost is emitted via
cost-updated. - UI surfaces cost in
Header.tsx($chip) andGraphDrawer.tsx(sorted monochrome bars).
src/engine/context.tsbuilds the orchestrator context underCONTEXT_BUDGET.- Always includes system prompt, objective, graph shape, available agents, and last 3 steps.
- Older steps are compacted into a one-line-per-step digest; full artifacts are only loaded on explicit full-read paths.
src/engine/worker.tshosts heavy engine work off the UI thread.src/engine/client.tsexposesrunMission,abortMission,ingestFile,searchKnowledge, anddestroy.- If
Workeris unavailable, it falls back to in-thread execution behind the same API.
src/engine/rag.tsprovides chunking, embedding, cosine search, and ingest/search bus events.knowledge_searchtool is attached to RESEARCHER and uses local embeddings only.- Dexie
chunkstable persists ingested text + embeddings; SIM mode can use pre-baked vectors. src/ui/components/FileDropZone.tsxprovides drag/drop + browse ingestion UI.
- Dexie
missionstable:id,objective,endedAt,steps,tokens,artifact - Dexie
artifactstable:id,missionId,nodeId,kind,summary,content,createdAt - Dexie
checkpointstable:missionId,status,currentStep,completedNodes,decisions,artifactIds,budgets,updatedAt - Dexie
chunkstable:id,missionScope,sourceFile,text,embedding,createdAt - Browser: localStorage/sessionStorage for keys, model overrides, speed, session-only flag, checkpoints
- Desktop:
tauri-plugin-strongholdfor secure key storage
- Space: run/pause
- Esc: close overlays
- Focus rings,
aria-livestatus, real buttons - Canvas:
role="img"with descriptivearia-label
Verified build on Linux (Fedora 42, x86_64). The native bundle compiles and produces .deb and .rpm.
Prerequisites:
- Rust toolchain (
rustup,cargo) - Linux system libraries (Tauri 2 webview + tray + stronghold):
sudo dnf install -y webkit2gtk4.1-devel libsoup3-devel gtk3-devel \ libappindicator-gtk3-devel librsvg2-devel openssl-devel patchelf # for AppImage output only (optional): sudo dnf install -y squashfs-tools - A Tauri icon set in
src-tauri/icons/(generate from any 1024×1024 PNG withpnpm tauri icon <png>).
Install Rust if missing:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | shBuild & release:
pnpm install
pnpm run tauri:dev # dev with hot reload (frontend on :1420)
pnpm run tauri:build # produces platform bundles in src-tauri/target/release/bundle
bash scripts/tauri-release.sh 2.1.0 # build + copy to release/ + create GitHub releaseNotes / fixes applied this release:
tauri.conf.json: removed the invalid Tauri-1platformskey (platforms are inferred from target).pnpm-workspace.yaml: requires a validpackagesfield orpnpm run buildfails in workspace mode.src-tauri/build.rs+Cargo.toml build = "build.rs"are required sotauri-buildruns codegen (generate_context!and capability validation).tauri-plugin-strongholdresolved to 2.3.1, whose API changed: there is noinit()— the plugin is registered viatauri_plugin_stronghold::Builder::with_argon2(&salt_path).build()inmain.rs.- Capability
default.jsonreferences onlycore:default+stronghold:default(thefs:permission was invalid becausetauri-plugin-fsisn't a dependency). - AppImage output needs
squashfs-tools(mksquashfs) and a working FUSE;.deb/.rpmdo not. - Windows (
.msi) cannot be produced from a Linux dev box (WiX/NSIS are Windows-native). It is built automatically by.github/workflows/release.ymlon GitHub'swindows-2022runner and published to the tag release alongside the Linux.deb/.rpm.
Cross-platform release:
git tag vX.Y.Z && git push origin vX.Y.Z # triggers the Release workflow (Linux + Windows)
# or: gh workflow run Release- TypeScript strict, no
any. Zod inference for protocol and output types. - No runtime third-party CDNs. Fonts are self-hosted.
- Recommended CSP:
connect-src https://openrouter.aior your proxy origin. - Budget guard: refuses missions when OpenRouter key usage ≥ limit − $0.05.
- Error mapping: 401 → AUTH, 402 → CREDITS, 429 → RATE with one retry.
- Per-node policy: transient errors retry with backoff; 401/402 stop mission; schema failures repair; model unavailable falls back once; escalation goes to human gate.
- Durable state: checkpoints written after every step and gate/policy event; resume on reload.
- Final gate: every
finalartifact passes deterministic checks plus independent critique; never crashes the mission on bad contracts. - Tauri 2 / Capacitor compatible: no SSR dependency, no CDN runtime fetches.
MIT







