xorafin
v1.0.0-beta.1
Published
Local-first AI agent CLI — run, test, and deploy agents with any LLM
Maintainers
Readme
Xorafin CLI
The local-first, trace-native agent runtime for your terminal.
Xorafin CLI (Forge) lets you define an agent once, run it locally with your own keys, inspect every step in a live TUI, test it repeatably, and promote it to hosted execution — without rebuilding anything.

What it is
Xorafin Forge is the terminal surface of the Xorafin agent operating layer. It is not a chatbot wrapper. It is a full agent runtime with:
- Swappable brain — automatically routes each input to the right model tier (fast / standard / best) based on task complexity. No manual model switching.
- 16 providers out of the box — OpenAI, Anthropic, Google, Groq, DeepSeek, xAI, Together, Fireworks, Cerebras, Perplexity, OpenRouter, Kimi, Ollama, LM Studio, and any OpenAI-compatible endpoint.
- Trace-native — every tool call, token, cost, and decision is logged to SQLite and replayable.
- Policy-controlled — budgets, stop conditions, tool consent, and approval gates are first-class config.
- Portable — one
agent.jsondefines the agent. It runs locally, in CI, or on the hosted control plane without changes.
Installation
npm install -g xorafinRequirements: Node.js 20+
Build from source
git clone https://github.com/itzzzzzzak/xorafin-cli.git
cd xorafin-cli
npm install
npm run build
npm linkQuick start
# 1. Create a new agent
xorafin init
# 2. Run it
xorafin
# 3. Or run one-shot (non-interactive)
xorafin run --input "summarise the files in this directory"Commands
| Command | Description |
|---|---|
| xorafin | Launch the interactive TUI (default) |
| xorafin init | Scaffold a new agent project (interactive wizard) |
| xorafin run --input <text> | Run a single turn non-interactively |
| xorafin config set <key> <value> | Set a config value (API keys, URLs, model tiers) |
| xorafin config get <key> | Get a config value |
| xorafin config list | List all config values |
| xorafin memory view | Inspect long-term memory |
| xorafin memory add | Add a memory fact |
| xorafin memory clear | Wipe all memories |
| xorafin skills list | List installed skills |
| xorafin skills learn | Add a new skill |
| xorafin test | Run agent test suite from YAML |
| xorafin bench | Benchmark agent turns (latency + cost) |
| xorafin checkpoint list | List saved checkpoints |
| xorafin checkpoint resume | Resume from a checkpoint |
| xorafin artifacts list | List files produced by the agent |
| xorafin vault set <key> | Store an encrypted secret |
| xorafin vault get <key> | Retrieve a secret |
| xorafin cron add | Schedule an agent run via OS task scheduler |
| xorafin trigger serve | Start a webhook trigger server |
| xorafin export | Bundle agent into a portable export |
| xorafin import <bundle> | Unpack an exported agent |
| xorafin push | Push agent to the Xorafin hosted control plane |
| xorafin runs | Browse and replay past runs |
| xorafin package validate | Validate agent.json |
Agent configuration
Every agent is defined by a single agent.json file:
{
"agent": {
"name": "my-agent",
"version": "1.0.0",
"description": "Does something useful."
},
"brain": {
"type": "swappable",
"default": "primary",
"available_brains": [
{
"id": "primary",
"provider": "openai",
"model": "auto",
"temperature": 0.2
}
]
},
"tools": {
"enabled": ["read", "write", "glob", "grep", "bash", "web_search", "memory_save"],
"builtin": {
"bash": { "consent": "ask" },
"write": { "consent": "ask" }
}
},
"memory": {
"long_term": { "type": "sqlite", "path": ".xorafin/memory.db" },
"working_context": { "path": "memory.md" }
},
"consent": { "default": "ask_dangerous" },
"budget": {
"max_cost_usd_per_run": 1.00,
"max_tokens_per_run": 200000
},
"stop_conditions": {
"max_steps": 25,
"max_tool_calls": 50,
"on_error": "continue"
}
}The agent's system prompt lives in prompt.md next to agent.json.
Swappable brain
Set model: "auto" and the engine classifies each input by task complexity, then routes to the appropriate model tier automatically.
| Tier | When | Example |
|---|---|---|
| fast | Greetings, short clarifications | "hi", "ok thanks" |
| standard | Single-topic questions | "explain what this agent does" |
| best | Code, debugging, multi-step tasks | "fix the bug in engine.ts" |
Each completed response shows which model and tier were used:
∙ 3,684 tok · $0.0006 · 2.2s gpt-4o-mini [fast]
∙ 32,381 tok · $0.0000 · 28.6s o3 [best]Override built-in tier defaults globally:
xorafin config set model_tiers '{"openai":{"fast":"gpt-4o-mini","standard":"gpt-4o","best":"o3"}}'Or per-agent in agent.json:
{
"id": "primary",
"provider": "openai",
"model": "auto",
"model_tiers": { "fast": "gpt-4o-mini", "standard": "gpt-4o", "best": "o3" }
}Providers
16 providers supported out of the box. Set keys once, use any provider in any agent.
| Provider | Key | Config key |
|---|---|---|
| OpenAI | OPENAI_API_KEY | openai_key |
| Anthropic | ANTHROPIC_API_KEY | anthropic_key |
| Google Gemini | GOOGLE_GENERATIVE_AI_API_KEY | gemini_key |
| Groq | GROQ_API_KEY | groq_key |
| DeepSeek | DEEPSEEK_API_KEY | deepseek_key |
| xAI (Grok) | XAI_API_KEY | xai_key |
| Together AI | TOGETHER_API_KEY | together_key |
| Fireworks AI | FIREWORKS_API_KEY | fireworks_key |
| Cerebras | CEREBRAS_API_KEY | cerebras_key |
| Perplexity | PERPLEXITY_API_KEY | perplexity_key |
| OpenRouter | OPENROUTER_API_KEY | openrouter_key |
| Kimi (Moonshot) | MOONSHOT_API_KEY | kimi_key |
| Ollama | (local, no key) | ollama_url |
| LM Studio | (local, no key) | lmstudio_url |
| Custom endpoint | (optional) | base_url |
xorafin config set openai_key sk-...
xorafin config set anthropic_key sk-ant-...
xorafin config set groq_key gsk-...Custom / unlisted providers
Point any brain at any OpenAI-compatible endpoint — no new packages, no SDK changes:
{
"id": "mistral",
"provider": "custom",
"model": "mistral-large-latest",
"base_url": "https://api.mistral.ai/v1",
"api_key_env": "MISTRAL_API_KEY"
}export MISTRAL_API_KEY=...api_key_env names the environment variable to read — the key never touches agent.json.
Built-in tools
| Tool | Description |
|---|---|
| read | Read a file |
| write | Write a file (consent gated by default) |
| update | Edit part of a file |
| glob | Find files by pattern |
| grep | Search file contents |
| ls | List a directory |
| bash | Run shell commands (consent gated) |
| web_search | Search the web |
| web_fetch | Fetch a URL |
| memory_save | Save a fact to long-term memory |
| memory_recall | Retrieve relevant memories |
| calculator | Evaluate math expressions |
| stock_price | Get a stock price |
Tool consent
Control which tool calls require user approval before executing:
| Mode | Behaviour |
|---|---|
| auto | All tools run without prompting |
| ask_dangerous | Prompts before bash, write, update (default) |
| ask | Prompts before every tool call |
Override per-tool in agent.json:
"tools": {
"enabled": ["bash", "write", "read"],
"builtin": {
"bash": { "consent": "ask" },
"write": { "consent": "ask_dangerous" },
"read": { "consent": "auto" }
}
}Memory
Agents have four memory layers:
| Layer | Purpose |
|---|---|
| Short-term | Rolling window of recent messages in-session |
| Long-term | Facts persisted across sessions in SQLite |
| Working context | memory.md file injected into every prompt |
| Procedural | Skills — reusable prompt-level playbooks |
xorafin memory view # inspect stored facts
xorafin memory add # add a fact manually
xorafin memory clear # wipe all factsTesting
Write test cases in YAML, run them with a single command:
# tests/test_cases.yaml
- name: basic greeting
input: "hi"
expect:
contains: ["hello", "assist"]
- name: file listing
input: "list the files in this directory"
expect:
contains: ["agent.json"]
tool_calls: ["ls"]xorafin test
xorafin bench # measure latency + cost per caseBudgets and stop conditions
Hard limits enforced per run — the agent stops before going over:
"budget": {
"max_cost_usd_per_run": 0.50,
"max_tokens_per_run": 100000
},
"stop_conditions": {
"max_steps": 20,
"max_tool_calls": 40,
"max_errors": 5,
"on_error": "continue"
}Vault
Encrypted local secret storage (AES-256-GCM):
xorafin vault set DATABASE_URL
xorafin vault get DATABASE_URLSecrets are stored in ~/.xorafin/vault.enc — never in agent.json or environment files.
Keyboard shortcuts
| Key | Action |
|---|---|
| Enter | Send message |
| Shift+Enter / Ctrl+J | New line |
| Ctrl+C | Interrupt current response |
| Ctrl+D | Exit |
| ↑ / ↓ | Browse input history |
| Ctrl+E | Expand / collapse tool output |
| Tab | Autocomplete slash command |
| ? | Toggle shortcut panel |
| /help | List all slash commands |
| /clear | Clear conversation |
| /verbose | Toggle verbose tool output |
| /memory | Open memory inspector |
| /skills | Open skills manager |
| /resume | Resume from last checkpoint |
Project structure
your-agent/
├── agent.json # Agent definition (brain, tools, memory, policy)
├── prompt.md # System prompt — the agent's "soul"
├── memory.md # Working context injected every turn (optional)
├── skills/ # Procedural skills (markdown playbooks)
│ └── example.md
├── tests/
│ └── test_cases.yaml # Repeatable test cases
└── .xorafin/
├── memory.db # Long-term SQLite memory store
└── traces/ # Per-run event tracesDevelopment
git clone https://github.com/itzzzzzzak/xorafin-cli.git
cd xorafin-cli
npm install
# Type check
npx tsc --noEmit
# Build (esbuild bundle → bin/xorafin.js)
npm run build
# Run directly from source
npx tsx src/main.tsxEntry point: src/main.tsx
Engine: src/runtime/engine.ts
Providers: src/runtime/providers.ts
Contributing
Bug fixes, new tools, provider support, and UX improvements are welcome. Please read CONTRIBUTING.md before opening a pull request.
Code of Conduct
This project follows the Contributor Covenant.
License
MIT — see LICENSE for details.
