Axion Code
Axion Code is the Go-first CLI agent harness for the Axion ecosystem. It brings the Axion Agent runtime to the terminal with PREVC + A workflow state, Mythos execution discipline, provider/model management, persistent sessions, shared Axion Desktop configuration, native dotcontext support, and a Claude Code-style TUI focused on agentic coding workflows.
This MVP follows the PREVC-P documentation package in .context/:
- Go core;
- PREVC + A / Mythos event rail;
- JSONL protocol for
run --json; - SQLite-first shared user session store;
- Claude Code-style terminal TUI powered by Bubble Tea;
- full-width chat layout with initial brand splash;
- provider catalog/profile foundation with mock and OpenRouter adapters;
- interactive slash palette and provider/model/permission menus;
- Axion Desktop fallback provider presets, including OpenAI-compatible and Anthropic-compatible endpoints;
- shared Axion Desktop/CLI provider, model and permission stores under
%USERPROFILE%\.axion; - Pi Agent assets in inspect/import-only mode;
- native dotcontext and MCP management posture;
- plan-scoped PREVC + A learning consolidation through
/learn; - shared plugin and native isolated subagent catalogs;
- native localhost browser control and Windows computer-use inspection commands.
MVP Commands
axion-code
axion-code ask "Explique este projeto"
axion-code ask --provider openrouter --model google/gemini-2.5-flash-lite "Responda em uma linha"
axion-code run --json
axion-code doctor --json
axion-code init --json
axion-code init --project --json
axion-code session list --json
axion-code remote-control start --ttl 24h --json
axion-code remote-control status --json
axion-code remote-control stop --json
axion-code remote-control pair --json < pair.json
axion-code remote-control intent --json < intent.json
axion-code remote-control events --json
axion-code remote-control seal --json < payload.json
axion-code remote-control open --json < secure-frame.json
axion-code remote-control relay --listen 127.0.0.1:8787 --json
axion-code browser dev start --command "npm run dev" --cwd . --json
axion-code browser open http://127.0.0.1:5173 --json
axion-code browser logs --duration 5s --json
axion-code browser eval --expr "document.title" --json
axion-code browser click --selector "button[type=submit]" --json
axion-code browser screenshot --path .context/runtime/browser/screenshot.png --json
axion-code computer-use status --json
axion-code computer-use screenshot --path .context/runtime/computer-use/screenshot.png --json
axion-code provider list --json
axion-code provider profile init
axion-code provider profile list --json
axion-code provider profile add or-free --catalog openrouter --model openrouter/free --credential-ref env:OPENROUTER_API_KEY
axion-code provider profile set or-free
axion-code provider profile delete or-free
axion-code provider profile active
axion-code provider model list openrouter --json
axion-code provider cost set openrouter --model openai/gpt-5-mini --max-usd 0.25 --input-usd-per-1m 0.25 --output-usd-per-1m 2 --max-output-tokens 4000
axion-code provider cost status --profile openrouter --model openai/gpt-5-mini --json
axion-code provider test openrouter google/gemini-2.5-flash-lite
axion-code permission list --json
axion-code permission set full_permission
axion-code permission inspect Bash "{\"command\":\"npm install left-pad\"}" --mode full_permission --json
axion-code permission request Bash "{\"command\":\"npm install left-pad\"}" --mode full_permission --json
axion-code permission approvals --decision pending --json
axion-code permission resolve <approval-id> --approve --reason "reviewed" --json
axion-code graphics doctor
axion-code graphics logo
axion-code graphics logo --mode sixel --width 180
axion-code mcp list --json
axion-code mcp add sample --command node --arg server.js
axion-code mcp enable sample
axion-code mcp disable sample
axion-code mcp remove sample
axion-code mcp import .\mcp-servers.json
axion-code plugins list --json
axion-code agents list --json
axion-code agents run bug-hunter "review this login flow"
axion-code agents run-many bug-hunter,performance-reviewer "review this login flow" --budget-tokens 2000 --stream
axion-code learn --json
axion-code memory status --json
axion-code memory recall "hooks safety" --json
axion-code memory curate --title "Pattern" --body "Apply this implementation pattern..." --json
axion-code hooks status --json
axion-code hooks add --event UserPromptSubmit --action inject --name Safety --content "Use trusted hook context only." --enabled
axion-code hooks enable
axion-code package inspect <path>
axion-code package self-check --json
remote-control intent --json validates the active paired lease and enqueues
accepted mobile intents for the owning TUI session. The TUI remains the executor:
user_message is dispatched as a normal local provider turn, tool_approval
resolves the existing approval queue, and provider/tool execution never moves to
the mobile client.
For local Axion Mobile development, run the loopback relay in one terminal:
axion-code remote-control relay --listen 127.0.0.1:8787
Then expose the active TUI session with:
/remote-control --relay ws://127.0.0.1:8787
Configure Mobile's auth/discovery endpoint as http://127.0.0.1:8787.
The relay exposes GET /remote-control/sessions, POST /remote-control/pair,
POST /remote-control/attachments and ws://127.0.0.1:8787/rc/<pairing_id>.
It is loopback-only, keeps provider/tool execution in the CLI and accepts mobile
intents only after SAS pairing.
Remote-control is bound to the authenticated Google email from Axion Desktop.
The CLI refuses to expose a remote URL without an active Desktop Google login.
Mobile discovery must send the same account email (X-Axion-Auth-Email or
auth_email) and pairing must include the same auth_email; mismatched emails
receive no session or are rejected. After a successful same-email pairing, the
host returns an access_token JWT signed with the derived pairing secret.
Mobile must use Authorization: Bearer <access_token> for the relay WebSocket
and attachment upload APIs. The token is never included in the public QR/status
payload.
Remote-control leases expire after 24h by default. Override one run with
/remote-control --ttl 2h or axion-code remote-control start --ttl 2h. Set
the local default in the TUI with /settings remote-control-ttl 24h; use
/settings remote-control-ttl never to keep the URL online while the local
Axion Code session is open.
When remote-control is active, the TUI footer shows mode remote-control in
green with Ctrl+U URL and Ctrl+Y QR. Press Ctrl+U to show and copy the
active remote URL again. Press Ctrl+Y to show and copy the full QR payload,
which avoids mouse-selection issues when the terminal selection crosses the
sidebar. Positional mouse capture is enabled by default so scroll stays scoped
to Timeline, Plan and Tasks and does not move the composer or whole terminal.
For terminal-native mouse selection, use /settings mouse text-select; restore
scoped scrolling with /settings mouse advanced.
Native Browser And Computer-Use
axion-code browser is the native localhost navigation plugin. It can start a
workspace-contained dev server, open a localhost URL in a supervised Chrome/Edge
instance, inspect console logs, evaluate JavaScript, click/type by CSS selector
and save page screenshots.
Browser control is intentionally local-only: accepted hosts are localhost,
127.0.0.1 and [::1], with localhost normalized to 127.0.0.1 for Windows
dev-server reliability. CDP binds to 127.0.0.1 and uses an isolated profile
under %USERPROFILE%\.axion\browser-control\profile.
axion-code browser dev start --command "npm run dev" --cwd . --json
axion-code browser open http://127.0.0.1:5173 --json
axion-code browser logs --duration 5s --json
axion-code browser eval --expr "document.title" --json
axion-code browser click --selector "button[type=submit]" --json
axion-code browser type --selector "input[name=q]" --text "Axion" --json
axion-code browser screenshot --path .context/runtime/browser/screenshot.png --json
axion-code browser dev stop --json
axion-code browser stop --json
axion-code computer-use is a guarded Windows MVP for desktop screenshot,
absolute-coordinate click, text entry and hotkeys. Mutating actions are
classified as high-risk browser-action tools and require approval unless the
active permission mode is YOLO.
axion-code computer-use status --json
axion-code computer-use screenshot --path .context/runtime/computer-use/screenshot.png --json
axion-code computer-use click --x 100 --y 200 --json
axion-code computer-use type --text "hello" --json
axion-code computer-use hotkey --keys ctrl+l --json
Install
Official install, after the package is published to the public npm registry:
npm install -g @rnbsolucoes/axion-code
axion
The GitHub source repository can remain private. The npm package is intentionally
published as a small installer/runtime package: it contains the Node wrapper,
platform binaries under npm/releases, and documentation, but it does not ship
the Go source tree (cmd/, internal/, go.mod, go.sum).
Private GitHub install is not the recommended distribution path. Commands like
npm install -g rnbsolucoes/Axion-CLI use Git access and may require SSH keys or
credentials on every machine. Use the scoped npm package instead.
Development install from the current local clone:
npm install -g .
axion
If an older local axion.ps1 shim already exists, replace it once:
npm install -g . --force
The npm package exposes both axion and axion-code. It does not use a
postinstall hook. On first run, the wrapper copies the packaged binary for the
current platform into the local Axion Code bin directory and then executes it. In
a source clone only, if no packaged binary exists, the wrapper can build from Go
as a development fallback.
Terminal setup (multi-line composer)
In the chat composer, Enter sends and Ctrl+J inserts a newline. Terminals do not report Shift+Enter or Ctrl+Enter as distinct keys to the app on Windows, so those keys must be mapped to send a newline.
On the first run, Axion does this automatically for Windows Terminal: it maps
Shift+Enter and Ctrl+Enter to send a newline (only when those keys are
free — it never overwrites an existing binding), writes a settings.json.axion-bak
backup, and prints a one-line notice. Reopen the terminal tab to apply. This runs
at runtime (not via an npm postinstall hook) and only once, tracked by a marker
in the local bin directory.
Opt out with AXION_SKIP_TERMINAL_SETUP=1. Re-apply or repair anytime with:
axion terminal-setup
On other terminals, bind Shift+Enter / Ctrl+Enter to send a newline (\n) manually.
To classify the currently executed binary for support or security review, run:
axion package self-check --json
The self-check reports the executable path, real path, runtime version,
SHA-256, file size, package cache marker when present and a provenance
classification such as npm-wrapper-cache, npm-package-release,
source-build or unknown-local-binary. It is deterministic local
provenance, not a replacement for future Authenticode signing.
Requirements:
- Node.js 18+ for the npm wrapper.
- End users do not need Go when installing from npm.
- Development source builds need Go 1.26+ on
PATH,AXION_GO, or the Codex bundled Go toolchain at%USERPROFILE%\.codex\toolchains\go1.26.4\go\bin\go.exe.
For this development machine, if an older PowerShell shim still points directly
to %LOCALAPPDATA%\AxionCode\bin\axion-code.exe, rebuild the local binary:
go build -o "$env:LOCALAPPDATA\AxionCode\bin\axion-code.exe" ./cmd/axion-code
Publish
Build the npm package binaries before publishing:
npm run build:npm-binaries:release
npm pack --dry-run
npm publish --access public
The npm account or organization must own the @rnbsolucoes scope. Scoped public
packages must be published with public access on the first publish.
The current release build targets Windows x64 and Linux x64. Add more targets by
running node npm/build-package-binaries.mjs --targets=all or a comma-separated
target list when those platforms are ready.
Update
Check for a newer version:
axion update --check
axion version --check
Update the installed CLI. This is the official update alias and must remain the single command users run whenever a new Axion Code binary/package is released:
axion update
The npm wrapper checks the public npm registry first and falls back to the GitHub package metadata only when available. If a newer version exists, the initial Axion Code splash shows the update notice and hides it after the first interaction.
Without npm:
go build -o "$env:LOCALAPPDATA\AxionCode\bin\axion-code.exe" ./cmd/axion-code
Provider catalog/configuration is shared with Axion Desktop, while the active Axion Code selection is isolated:
%USERPROFILE%\.axion\harness\providers.json
%USERPROFILE%\.axion\harness\active_profile # Axion Desktop active profile
%USERPROFILE%\.axion\harness\active_profile_cli # Axion Code active profile
%USERPROFILE%\.axion\harness\selection_cli.json # Axion Code active model/params
%USERPROFILE%\.axion\axion-mode.json
%USERPROFILE%\.axion\sessions\axion.db
%USERPROFILE%\.axion\mcp-servers.json
%USERPROFILE%\.axion\plugins.json
%USERPROFILE%\.axion\sub-agents.json
%USERPROFILE%\.axion\harness\cost-policy.json
OpenRouter uses OPENROUTER_API_KEY from the environment or a secret:<NAME> reference stored in C:\Israel\Pesoal\secrets.env (override for tests: AXION_SECRETS_ENV). Provider profile config stores only references, never the key value.
Provider-specific cost ceilings are stored outside the Desktop profile schema in
%USERPROFILE%\.axion\harness\cost-policy.json. Use provider cost set to
bind a ceiling and token prices to a profile or profile/model pair. The runtime
blocks a request before provider execution when the estimated input or configured
maximum output cost would exceed the ceiling. After a response, actual
input/output usage is converted to cost and surfaced in provider/subagent stream
telemetry; if actual cost exceeds the ceiling, the turn returns an explicit cost
ceiling error. A ceiling without token prices is not enforced, because Axion Code
does not infer provider pricing silently.
For test/dev isolation, set AXION_HOME to a temporary folder. In normal use,
leave it unset so Desktop and CLI share the same provider catalog while keeping
their active provider/model selections independent.
Project Bootstrap
axion-code init --json bootstraps the shared user-level Axion home used by
Axion Desktop and Axion Code. It creates missing files under
%USERPROFILE%\.axion without overwriting Desktop-owned provider/model state.
axion-code init --project --json bootstraps the current workspace. The same
operation is available inside the TUI with /init. It creates only missing
project scaffolding:
.brv/ local operational memory and PREVC + A learning buffers
.context/ workflow, plans, tasks, context snapshots and PREVC evidence
.docs/ project documents, specs, reports and handoff material
AGENTS.md project-scoped instructions
CLAUDE.md Claude-compatible project instructions
.gitignore ignored local runtime, secrets, cache and build-output patterns
If a legacy docs/ directory exists and .docs/ does not, project bootstrap
renames docs/ to .docs/. If both exist, Axion Code leaves both untouched and
does not attempt an automatic merge.
Instruction layering is explicit: shared %USERPROFILE%\.axion\AGENTS.md
contains global Axion Code agent rules, while the workspace root AGENTS.md
contains project-specific rules. Provider runtime prompts read both layers when
present, plus CLAUDE.md as a compatibility surface.
The interactive TUI supports:
/ inline slash palette
/init
/provider
/provider set <profile-id>
/model
/permission
/mcp
/learn
/memory
/hooks
/plugins
/agents
/agents run <id> <prompt>
/agents run-many <id,id,...> <prompt> [--budget-tokens <n>]
Slash palette behavior: ↑/↓ selects, Tab completes the selected command, Enter executes the selected command, Esc closes active menus/wizards.
/model pulls the active provider's /models endpoint when credentials are configured. Reasoning and fast-mode steps appear only when the selected model metadata exposes those parameters.
/learn consolidates plan-scoped learning from .brv/plans/<plan-id> and .context/learning-candidates*.md, filters low-signal material, deduplicates by content hash/summary and promotes relevant notes into native dotcontext at <workspace>/.axion/context.
/memory exposes the native project memory layer: status, ensure, recall <query> and curate <text>. Recall uses the local .axion/context note tree plus a SQLite FTS index and injects bounded ## Memoria recuperada context into provider prompts without changing the visible/stored user message.
/hooks exposes Phase 1 native hooks. Hooks are stored in shared %USERPROFILE%\.axion\hooks.json and controlled by %USERPROFILE%\.axion\hooks-config.json, default OFF. SessionStart and UserPromptSubmit can inject trusted <hook-context> prompt context; PostToolUse and Stop are observe-only. Phase 1 does not execute shell commands or approve tools.
When the active plan comes from .context/plans/*.md, /task add, /task done
and /task progress update the Markdown plan file directly. Axion Code rewrites
only the target task line marker/progress and keeps the rest of the document
unchanged.
/mcp opens an inline MCP list. Enabled servers can be disabled, disabled servers can be enabled, and non-native servers can be uninstalled while preserving valid mcp-servers.json formatting.
/agents lists the native isolated subagents. /agents run <id> <prompt> calls one with an isolated prompt while inheriting the active provider/model from the main agent. /agents run-many <id,id,...> <prompt> [--budget-tokens <n>] runs up to eight isolated subagents in parallel, streams lifecycle/telemetry events into the TUI while the team runs, then returns their individual outputs plus a compact comparison and aggregate token usage. If the estimated isolated prompt input already exceeds the budget, no provider calls are executed.
MCP, Plugins And Subagents
MCP import files use the same JSON array shape as %USERPROFILE%\.axion\mcp-servers.json:
[
{
"id": "context7",
"name": "Context7",
"transport": "stdio",
"command": "npx",
"args": ["-y", "@upstash/context7-mcp"],
"enabled": false,
"read_only": true
}
]axion mcp import <file.json> merges by id, preserves native protection for built-ins, writes formatted JSON, and rejects entries without id or without the required command/url for the selected transport. Native MCPs such as dotcontext cannot be removed, only disabled.
axion mcp tools <id> [--json] starts an enabled stdio MCP server, performs the MCP initialize handshake and returns the exact tools advertised by tools/list. This is the recommended smoke test for native MCPs before enabling provider tool calls, for example axion mcp tools axion-dotcontext --json.
The native Dotcontext MCP uses the current official package surface, npx -y @dotcontext/mcp@latest. Existing shared Axion homes are migrated from the deprecated dotcontext npm package to @dotcontext/mcp@latest during bootstrap while preserving local MCP status metadata. Because the native entry points at @latest, normal MCP startup pulls upstream Dotcontext server updates; Axion code changes are needed only when Dotcontext changes package names, tool contracts or Axion-specific integration policy.
Plugins are read from the same shared Axion Desktop file, %USERPROFILE%\.axion\plugins.json. The CLI can list, enable, disable and remove plugin records, but executable plugin installation remains intentionally gated for the next trust-policy cycle.
Subagents are stored in %USERPROFILE%\.axion\sub-agents.json. The initial catalog has 15 native entries:
- Programming:
code-reviewer,bug-hunter,security-reviewer,performance-reviewer,frontend-ux-reviewer. - Professional:
product-strategist,business-analyst,financial-analyst,legal-policy-reviewer,marketing-strategist,sales-ops-analyst,customer-success-advisor,data-analyst,operations-advisor,hr-talent-advisor.
Execution contract: subagents inherit the active provider/model, receive an isolated prompt containing only their role and the requested task, do not access the main hidden context unless explicitly included in the prompt, and return findings/evidence/actions back to the main timeline.
Approval And Sandbox Policy
axion permission inspect exposes the native Go approval policy without running
the tool. It classifies native tools, shell commands and MCP-proxied tools into
stable risk classes, reports whether the active permission mode would require
approval, redacts secret-shaped inputs and returns the sandbox profile that the
guarded dispatcher must use.
axion permission request|approvals|resolve adds the auditable approval queue.
Requests are persisted in the shared session database under
%USERPROFILE%\.axion\sessions\axion.db with the redacted decision, risk class,
permission mode, impact summary and pending/approved/denied state. This is the
headless contract used by the TUI approval menu and the future guarded
dispatcher before mutating filesystem, shell or MCP tools are enabled.
Provider stream tool_call events now open the TUI approval menu when the
active permission mode requires review. Approve/Deny records the audited
decision and returns focus to the chat input. When approved, the TUI executes
supported guarded-dispatcher tools and prints the bounded result in the
timeline. Successful supported tool results are then sent back into the active
provider as a follow-up tool_result continuation turn, so the agent can use
the evidence before answering. Unsupported tools remain explicitly pending until
a dedicated adapter exists.
axion tool run exposes the guarded dispatcher surface. The CLI and TUI
currently support workspace-local Read, Glob, Grep, Write and Edit,
governed Shell/Bash/PowerShell commands that run from a workspace
directory with timeout and bounded output, enabled stdio MCP tools named as
mcp__<server-id>__<tool-name>, native localhost browser_* tools and guarded
Windows computer_* tools. Provider tool aliases such as read_file,
write_file and run_command are normalized to native tool names before
approval/execution. When the active permission mode requires approval, execution
is allowed only if the supplied approval is already approved and matches the
exact redacted tool request. Remote MCP transports, arbitrary process tools and
unknown tools remain unsupported even when an approval exists.
Examples:
axion permission inspect Read --mode approved_by_me --json
axion permission inspect Bash "{\"command\":\"npm install left-pad\"}" --mode full_permission --json
axion permission inspect mcp__serena__replace_symbol_body "{}" --mode full_permission --json
axion permission request Bash "{\"command\":\"npm install left-pad\"}" --mode full_permission --session smoke --turn turn-1 --json
axion permission approvals --session smoke --decision pending --json
axion permission resolve <approval-id> --deny --reason "not needed" --json
axion tool run Read "{\"path\":\"README.md\"}" --mode full_permission --json
axion tool run Write "{\"path\":\"notes/out.txt\",\"content\":\"approved\"}" --session smoke --turn turn-1 --approval <approval-id> --mode request_permission --json
axion tool run Shell "{\"command\":\"echo axion-shell\"}" --session smoke --turn turn-1 --approval <approval-id> --mode request_permission --json
axion mcp tools axion-dotcontext --json
# Shape: replace server/tool with an enabled MCP tool advertised by tools/list.
axion tool run mcp__your-server__list_items "{\"query\":\"PREVC\"}" --mode full_permission --json
Security invariants:
Full permissionskips only read and non-destructive write tiers.- package install, network download/egress, destructive commands, process
control, shell commands, paid generation, browser actions, mutating MCP tools
and unknown tools still require approval under
Full permission. YOLOis the only mode that bypasses every class, and remains explicit user opt-in.- unknown native tools are default-deny until they are classified.
- MCP tools are mutating by default; only read-shaped names such as
find_*,get_*,list_*,search_*and*_overvieware downgraded to read-only. The dispatcher validates that enabled stdio MCP servers advertise the target tool throughtools/listbefore callingtools/call.
Provider menu actions:
Register provider
Edit provider
Set provider
Delete provider
For a profile-backed OpenRouter session:
axion provider profile add or-free --catalog openrouter --model openrouter/free --credential-ref env:OPENROUTER_API_KEY
axion provider profile set or-free
axion
Nexus profiles share the same %USERPROFILE%\.axion\harness\nexus-config.json
used by Axion Desktop. The default fusion engine runs the existing
panel -> judge -> final flow. The pcp engine enables the text-only
Maestro/workers loop from the new Desktop Nexus provider:
axion provider nexus status --profile nexus
axion provider nexus set --profile pcp-nexus --engine pcp --judge-kind sakana --judge sakana:fugu --image-provider imagehub --image-model image-default --video-provider videohub --video-model video-pro --exec3 mock:mock/worker --exec3-instruction "general text worker"
PCP in the CLI supports Maestro tool-calling with text workers exec3 and
exec4, plus image/video slots exposed as internal PCP workers. Nexus streams
normalized lifecycle telemetry to the TUI for Fusion and PCP phases; internal
PCP worker dispatches stay private and do not surface as app-level tool
approvals. Image/video dispatch is refused unless permission mode is yolo;
even in yolo, the CLI currently returns a structured "media runtime
unavailable" tool result until the local media runtime lands. When Axion
Desktop saves PCP image/video slots as model-only capability references, the CLI
resolves the provider label from Desktop's capability_selections store on a
best-effort basis for status, audit metadata and worker labels.
Build
go test -count=1 ./...
go build ./cmd/axion-code
If Go is not on PATH, use a verified local Go toolchain and keep generated binaries out of git.
Current Limits
This is a functional direction MVP, not the full harness:
- direct provider streaming exists for OpenAI-compatible chat completions, OpenAI Responses and Anthropic Messages;
- Nexus supports the legacy Fusion engine and the new PCP Maestro/workers engine with stream normalization, redacted audit surfacing, TUI Nexus configuration, text workers and permission-gated image/video worker placeholders; real CLI media generation remains deferred;
- terminal logo uses Sixel when available and falls back to width-bounded ANSI/block rendering;
- initial chat splash shows the Axion logo and system name until the first interaction;
- guarded dispatcher execution includes workspace-local
Read,Glob,Grep,WriteandEdit, governed workspace-scoped shell commands, enabled stdio MCP tools, native localhostbrowser_*tools and guarded Windowscomputer_*tools; the TUI executes these after approval and shows the result, then feeds successful supported results back into the provider as an iterativetool_resultcontinuation turn; - remote MCP transports, arbitrary process control and unknown tools remain blocked;
- no executable Pi RPC bridge yet;
- native subagent execution is prompt-isolated and provider/model-inherited;
agents run-manyprovides parallel fan-out, compact comparison, aggregate usage, a token budget ceiling and streamed lifecycle/telemetry events. Provider/model cost ceilings are enforced by the shared Axion cost policy.