The agent framework where every block is swappable.
Bring your own model. Bring your own loop. Bring your own tools β and run it from your terminal, your desktop, or a phone.
Get started Β Β·Β Why moxxy Β Β·Β See it Β Β·Β Docs Β Β·Β Channels Β Β·Β Built by itself Β Β·Β Developer guide
Moxxy.ai_video.mp4
~95% of moxxy is written by moxxy β the agent builds the framework, and the framework runs the agent. (For comparison, Anthropic has said Claude writes ~80% of Claude Code.) That number isn't a gimmick or a license to ship slop; it's a forcing function for the opposite. When the machine that writes the code is the same machine you're shipping, engineering discipline becomes the product, and you get to apply it at a scale and speed a human-only team can't match.
What that discipline looks like here, in practice:
- Adversarial self-review, not vibes. Findings are produced by fan-out analysis agents and then handed to independent agents whose only job is to refute them β false positives die before they reach a human. A recent full-codebase audit ran dozens of agents this way, surfaced 47 confirmed issues across security, stability, performance and packaging, and fixed every one in verified, single-concern PRs.
- Every change runs the gate. Build, typecheck, lint, and the full test suite (thousands of tests across ~50 packages) pass on three Node versions before anything merges β enforced in CI and locally by git hooks so the agent can't declare done on a red tree.
- Real-world, not just mocked. A one-press live E2E workflow drives the actual CLI against the real OpenAI API β a streaming turn, a tool round-trip, and a confirmed SSRF-guard refusal of a cloud-metadata address β so security and provider behavior are proven against production, not fixtures.
- The codebase teaches the next agent. A living tech-debt journal (retire-one-per-change), a skill library of thin, single-purpose playbooks, and specialized agent definitions mean each change leaves the repo easier to change correctly β compounding quality instead of eroding it.
The result is delivery that's faster (parallel agents, hours not weeks), cleaner (one concern per PR, every claim cited to a file and line), and more robust (adversarial verification + live validation + a gate nothing skips) than a conventional pipeline β because the author is an agent held to a higher bar, not in spite of it.
Want to see the machinery? Start with
.claude/skills/,TECH_DEBT.md, and the Developer guide.
npm install -g @moxxy/cli # or: npx @moxxy/cli initmoxxy onboard # guided: provider β messaging channel (Discord/Telegram/β¦) β pairing β background service
moxxy # launch the interactive TUIPrefer the pieces? moxxy init does just the provider wizard; moxxy <channel> sets up one channel; moxxy service install serve makes it permanent.
One-shot, straight from the shell:
moxxy -p "summarize the README in three bullets"Already running? Keep it current:
moxxy update # checks npm and upgrades in place (the TUI also nudges you when a new version ships)Requirements: Node.js β₯ 20.10 and an API key for a supported provider (Anthropic, OpenAI, or ChatGPT/Claude via OAuth). moxxy --help lists every command.
Most agent frameworks lock you in. One LLM provider. One loop topology. One frontend. One opinionated way the agent should behave.
moxxy doesn't. Every block is a plugin. Swap Anthropic for OpenAI. Swap the default loop for goal (autonomous, auto-approve) or research (parallel fan-out + cited synthesis). Drive the same Session from your terminal, the desktop app, Telegram, or an HTTP endpoint β at the same time. Install a package and it's auto-discovered; nothing to wire by hand.
| π§© Truly modular | Every block is a swappable plugin: provider, loop strategy, tools, compactor, cache strategy, channel. |
| π Plug-and-play | Install a package, it's auto-discovered. Hot-reload without restarting. |
| π€ Multi-channel | TUI, desktop app, Telegram, HTTP. One Session, many surfaces. |
| π Voice in | Telegram voice notes or POST raw audio to the HTTP channel. Whisper ships built-in; swap to Deepgram or local whisper.cpp by registering a different Transcriber. |
| π Secrets done right | Built-in AES-256-GCM vault. OS keychain by default, passphrase fallback. |
| π§ Long-term memory | Journal-based with vector recall. TF-IDF ships built-in; swap to OpenAI embeddings. |
| π Type-safe SDK | Zero-runtime-dep @moxxy/sdk is the contract. Author plugins with full IDE support. |
| β° Always-on | moxxy service install turns any channel into a launchd / systemd service, or moxxy serve --background runs everything in one shared-session process. |
| π Webhooks | Any system can fire prompts: verified (HMAC / bearer), filtered, idempotent. Auto-tunneled with cloudflared for a one-command public URL. |
| πͺͺ Permissions | Every tool call gated. Allow-always rules learned per tool over time. |
| π‘ Pluggable isolation | Opt-in capability sandboxing. Tools declare what they need (fs paths, hosts, time / memory); an Isolator enforces. inproc built-in; worker / subprocess / wasm / docker drop in behind the same interface. Off by default. |
Run your agent through whatever surface fits the task:
| Channel | What it does | Command |
|---|---|---|
| TUI | Interactive terminal UI | moxxy |
| Desktop | Native multi-workspace app (Electron) | download |
| Telegram | Message your agent from anywhere; voice notes transcribed and run as turns; pairs with a 6-digit code | moxxy telegram |
| HTTP | POST /v1/turn (JSON, SSE streaming) or POST /v1/turn/audio (raw bytes, iOS Shortcut friendly), bearer-token auth |
moxxy channels http |
| Cron | Time-driven prompts (cron expressions or one-shot ISO timestamps) | moxxy schedule add β¦ |
| Webhooks | External systems fire prompts on signed POST. HMAC + bearer + filter rules. | moxxy serve (auto-starts the listener) |
Keep them online 24/7 as background OS services. Two paths:
# Per-channel units (one process each, independent crashes)
moxxy service install telegram # launchd on macOS, systemd --user on Linux
moxxy service logs telegram # tail the log
# Or: one process for everything, shared event log
moxxy serve --background # every channel + scheduler + webhooks
moxxy serve --background --except http # skip what you don't want
moxxy serve --status # is it running?Logs land in ~/.moxxy/services/<name>.log; units survive reboots.
- Providers: Anthropic, OpenAI, Codex (ChatGPT OAuth), Claude (Pro/Max OAuth). Add your own with one
defineProvider({}). - Loop strategies:
default(Claude-Code-style ReAct loop),goal(autonomous auto-approve loop β runs across turns untilgoal_complete),research(plan queries β parallel subagent fan-out β cited synthesis). Switch in the TUI with/mode. - Built-in tools: Read, Edit, Write, Bash, Grep, Glob, recall, Sleep β plus
web_fetch(via@moxxy/plugin-browser), computer-control (macOS), and browser sessions (Playwright). - Prompt caching:
@moxxy/cache-strategy-stable-prefixplaces deterministic cache breakpoints (static tools/system/stable-prefix + a rolling tail) so the inner iterations of a turn read the prompt from cache instead of paying full price. Provider-neutral; swap it or disable with thenonestrategy. Inspect savings live with/usage. - MCP: register any Model Context Protocol server as a tool source.
- Skills: prompt-only Markdown files. The agent can author new skills for itself when no existing skill fits.
- Memory: long-term journal + STM event-log selectors. TF-IDF vector recall built in; swap to OpenAI embeddings via
@moxxy/plugin-embeddings-openai. - Webhooks:
@moxxy/plugin-webhooksships a verified HTTP listener, include/exclude filters (headers + JSON paths), delivery idempotency, and acloudflared/ngroktunnel helper. - Voice in (STT):
@moxxy/plugin-stt-whisperships an OpenAI WhisperTranscriber. Wire it once and every channel with audio input routes through it. Swap to Deepgram, AssemblyAI, or localwhisper.cppby registering a differentTranscriber. - Vault: AES-256-GCM at rest. Reference secrets in config as
${vault:KEY}. - Security / isolation:
@moxxy/plugin-securityβ opt-in capability sandboxing. Tools declare anisolation: { capabilities }spec ondefineTool({...})(fs path globs, net host allowlist, env keys,timeMs,memMb); when enabled, anIsolatorenforces those bounds at every call. Shipsnone+inproc; stronger modes (worker_threads, subprocess, wasm, Docker) register through the same SDK interface. Off by default β enable viamoxxy initorsecurity.enabled: true.
Full docs at docs.moxxy.ai: concepts, recipes, plugin authoring, channel guides. Marketing site: moxxy.ai.
Everything below is for plugin authors, contributors, and folks embedding moxxy in their own TypeScript apps.
import { Session, runTurn, autoAllowResolver } from '@moxxy/core';
import { anthropicPlugin } from '@moxxy/plugin-provider-anthropic';
import { builtinToolsPlugin } from '@moxxy/tools-builtin';
import { defaultModePlugin } from '@moxxy/mode-default';
const session = new Session({ cwd: process.cwd(), permissionResolver: autoAllowResolver });
session.pluginHost.registerStatic(anthropicPlugin);
session.pluginHost.registerStatic(builtinToolsPlugin);
session.pluginHost.registerStatic(defaultModePlugin);
session.providers.setActive('anthropic');
for await (const event of runTurn(session, 'list TS files in cwd')) {
if (event.type === 'assistant_chunk') process.stdout.write(event.delta);
}import { definePlugin, defineTool, z } from '@moxxy/sdk';
export default definePlugin({
name: '@acme/moxxy-plugin-greet',
tools: [
defineTool({
name: 'greet',
description: 'Return a greeting for the given name.',
inputSchema: z.object({ name: z.string() }),
handler: ({ name }) => `Hello, ${name}!`,
}),
],
});Add a "moxxy" block to your package.json and moxxy auto-discovers it:
{
"moxxy": { "plugin": { "entry": "./dist/index.js", "kind": "tools" } }
}Per-block author guides live in .claude/agents/, one per surface (skill, plugin, tool, channel, provider, loop strategy, compactor, cache strategy).
moxxy.config.ts at your project root:
import { defineConfig } from '@moxxy/config';
export default defineConfig({
provider: {
name: 'anthropic',
model: 'claude-sonnet-4-6',
config: { apiKey: '${vault:ANTHROPIC_API_KEY}' }, // resolved from the vault
},
mode: 'default',
plugins: {
'@moxxy/plugin-browser': { enabled: false }, // disable a plugin (or use `moxxy plugins disable`)
},
});${vault:NAME} placeholders are resolved on session start. The vault unlocks via OS keychain (keytar) with a passphrase fallback (MOXXY_VAULT_PASSPHRASE for headless boxes).
Provider keys (ANTHROPIC_API_KEY, OPENAI_API_KEY, β¦) are picked up automatically. Everything moxxy-specific:
| Variable | Effect |
|---|---|
MOXXY_HOME |
Override the ~/.moxxy data directory (vault, skills, sessions, services). |
MOXXY_DEBUG=1 |
Verbose CLI error output + process-guard diagnostics. |
MOXXY_VAULT_PASSPHRASE |
Headless vault passphrase (alternative to the OS keychain). |
MOXXY_SESSION_ID |
Sticky session id for moxxy serve β resume this persisted session instead of booting a fresh one. |
MOXXY_RUNNER_SOCKET |
Override the runner's unix-socket path. |
MOXXY_NO_CORE_UPDATE=1 |
Don't register the Tier-2 core self-update tools. |
MOXXY_FIXTURES |
record | replay | passthrough β provider fixture mode (tests). |
MOXXY_TELEGRAM_TOKEN |
Override the vault-stored Telegram bot token. |
MOXXY_HTTP_TOKEN |
Bearer token for the HTTP channel. |
MOXXY_WEB_TOKEN |
Auth token for the web surface channel. |
MOXXY_NO_WEB_SURFACE=1 |
Skip starting the web surface in moxxy serve. |
MOXXY_MOBILE_TOKEN |
Bearer token for the mobile channel's WebSocket bridge. |
MOXXY_MOBILE_HOST |
Bind host for the mobile channel (default 127.0.0.1; 0.0.0.0 exposes it on the LAN). |
MOXXY_MOBILE_TUNNEL |
localhost | cloudflared | ngrok β tunnel for the mobile channel. |
MOXXY_VOICE_AUDIO_DEVICE |
Audio capture device for TUI voice input. |
MOXXY_MCP_STDERR=inherit |
Surface MCP server stderr (default: ignored). |
MOXXY_WS_BRIDGE=1 |
Desktop: enable the WebSocket IPC bridge for remote clients (the mobile app). |
MOXXY_WS_PORT / MOXXY_WS_HOST / MOXXY_WS_TOKEN |
Desktop bridge port / bind host / auth token (token auto-generated when unset). |
MOXXY_WS_ALLOW_QUERY_TOKEN=1 |
Desktop bridge: also accept the legacy ?t= query-string token (off by default; native clients use the Sec-WebSocket-Protocol bearer). |
MOXXY_RUNNER_STRICT_ABORT=1 |
Runner: deny cross-client turn aborts instead of allowing + audit-logging them. |
MOXXY_CLI_ENTRY |
Desktop: explicit path to the CLI entry used to spawn runners. |
MOXXY_CHATS_DIR |
Desktop: override the NDJSON chat-log directory (default ~/.moxxy/chats). |
MOXXY_UPDATE_URL |
Desktop: override the self-update manifest URL. |
MOXXY_UPDATE_SIGNING_KEY |
CI only: private key used to sign desktop app bundles. |
MOXXY_APP_BUNDLE_ROOT / MOXXY_APP_BUNDLE_VERSION |
Set internally by the desktop bootstrap loader β not user-set. |
@moxxy/sdk β typed public surface (zero runtime deps)
@moxxy/core β runtime: event log, registries, plugin host, permissions, skills
@moxxy/tools-builtin β Read / Edit / Write / Bash / Grep / Glob
@moxxy/mode-default β "default" mode: Claude Code-style ReAct loop (active by default)
@moxxy/mode-goal β "goal" mode: autonomous auto-approve loop (runs until goal_complete)
@moxxy/mode-deep-research β "research" mode: multi-query fan-out + cited synthesis
@moxxy/plugin-provider-anthropic β LLM provider
@moxxy/plugin-provider-openai β LLM provider
@moxxy/plugin-provider-openai-codex β ChatGPT OAuth provider
@moxxy/plugin-provider-claude-code β Claude Pro/Max OAuth provider
@moxxy/plugin-provider-admin β register OpenAI-compatible providers at runtime
@moxxy/plugin-mcp β MCP servers as tool sources
@moxxy/plugin-vault β encrypted secrets
@moxxy/plugin-memory β journal LTM + vector recall + STM selectors
@moxxy/plugin-embeddings-openai β neural embeddings (optional)
@moxxy/plugin-embeddings-transformers β on-device embeddings via transformers.js
@moxxy/plugin-stt-whisper β OpenAI Whisper Transcriber (voice in)
@moxxy/plugin-stt-whisper-codex β Whisper Transcriber via the ChatGPT OAuth creds
@moxxy/plugin-browser β headless Playwright sidecar + web_fetch
@moxxy/plugin-computer-control β macOS native input (screenshot, click, type, β¦)
@moxxy/plugin-oauth β generic OAuth 2.0 + PKCE / device-code
@moxxy/plugin-cli β Ink TUI + TuiChannel
@moxxy/plugin-telegram β TelegramChannel via grammy (text + voice)
@moxxy/plugin-channel-http β HTTP channel (POST /v1/turn, /v1/turn/stream, /v1/turn/audio)
@moxxy/plugin-channel-web β web surface channel (browser app rendering view-spec UIs over a WebSocket)
@moxxy/plugin-channel-mobile β mobile channel (desktop IPC contract over an authenticated WebSocket; `moxxy mobile`)
@moxxy/plugin-view β present_view tool: agent-authored JSX-like view-specs β validated AST
@moxxy/plugin-scheduler β time-driven prompts
@moxxy/plugin-webhooks β external-event triggers (verified HTTP listener + tunnels)
@moxxy/plugin-workflows β swappable DAG engine: chain skills/prompts/tools into saved, schedulable pipelines
@moxxy/plugin-security β opt-in capability isolation (Isolator interface + none/inproc impls)
@moxxy/isolator-worker β worker_threads Isolator (memory + time + JS-state isolation)
@moxxy/isolator-subprocess β subprocess Isolator (kernel-enforced process boundary)
@moxxy/isolator-wasm β WebAssembly Isolator (zero ambient authority; experimental)
@moxxy/plugin-subagents β spawn sub-agents from a turn
@moxxy/plugin-commands β built-in slash commands (/info, /clear, /compact, β¦)
@moxxy/plugin-self-update β agent edits its own plugins/skills (Tier 1) + core (Tier 2)
@moxxy/plugin-plugins-admin β install / remove / enable / disable plugins at runtime (model tools + `moxxy plugins` CLI + `/plugins` picker)
@moxxy/plugin-usage-stats β per-session token + cost accounting
@moxxy/compactor-summarize β default context-window compactor
@moxxy/cache-strategy-stable-prefix β default prompt-cache strategy (deterministic breakpoints; `none` opts out)
@moxxy/skills-builtin β Markdown skills bundled with the framework
@moxxy/runner β bare session runner; channels attach over a unix socket (JSON-RPC)
@moxxy/cli β the `moxxy` binary
@moxxy/config β defineConfig + moxxy.config.ts loader
@moxxy/testing β FakeProvider + record/replay harness
@moxxy/chat-model β UI-neutral chat model (eventβblock fold + markdown AST + chunked log); shared by the TUI and desktop
apps/desktop β Electron desktop app (attaches to @moxxy/runner)
@moxxy/desktop-ipc-contract β typed desktop IPC boundary (channels + payloads + Zod validation + error envelope)
@moxxy/desktop-host β desktop Electron main process (runner pool/supervisor, IPC, NDJSON chat log, security)
@moxxy/desktop-ui β framework-light React UI primitives (Icon set, Modal, Skeleton); shared by the renderer
@moxxy/client-core β DOM-free headless client layer (stores + use* hooks + transport seam + platform capabilities)
@moxxy/client-platform-web β web platform capabilities for client-core (mic capture, Web Speech TTS, localStorage KV)
@moxxy/client-transport-ws β MoxxyApi over a WebSocket JSON-RPC client (global WebSocket; Metro/RN-safe)
@moxxy/ipc-server-ws β serves the desktop IPC contract over an authenticated WebSocket (bearer-token handshake)
@moxxy/design-tokens β framework-neutral design tokens + :root CSS-variable generator
The hard invariant: @moxxy/sdk has zero internal deps; @moxxy/core doesn't import any plugin. Enforced in CI via pnpm check:deps.
packages/ publishable @moxxy/* packages
apps/ desktop app, mobile (Expo) PoC, docs site, fixture-recorder
assets/ README media (mascot + demo gifs)
tooling/ shared tsconfig + eslint + vitest preset
.claude/agents/ AI-agent author guides (skill, plugin, tool, channel, provider, compactor, cache strategy, β¦)
AGENTS.md index for AI agents working in this repo
pnpm install
pnpm -r build
pnpm -r typecheck
pnpm -r test # 250+ tests across the workspace
pnpm check:deps # architectural invariant check (SDK & core stay clean)CI runs all of the above on every push + PR.
PRs welcome. Open an issue first for anything non-trivial. Per-block author guides in .claude/agents/ describe how to write skills, plugins, tools, channels, providers, loop strategies, compactors, and cache strategies.
moxxy is permission-gated and vault-protected by default, isolatable on demand: every tool call passes the permission engine, secrets live in an AES-256-GCM vault the model only ever sees as ${vault:KEY} references, and opt-in capability isolation can sandbox tools per-call. Threat model, hardening guidance, and how to report a vulnerability: SECURITY.md.
MIT.


