a terminal coding agent
Teach it once.It remembers forever.
haxford writes its own skills to disk, so a fix you make today is a trick it already knows tomorrow — in this project, and every one after. One binary, your own provider keys, and nothing left running when you close the terminal.
curl -fsSL https://haxford.dev/install.sh | bash
# Re-run anytime to upgrade: haxford updatewhy haxford
It extends itself
Ask for a skill, extension, or theme and haxford writes its own files under ~/.haxford — then /reload makes them live in the running session. There's no plugin API to learn, because the plugin format is markdown.
Your keys, your spend
Eight providers under your own keys — Anthropic, OpenAI, OpenRouter, Ollama, Z.AI, Moonshot, opencode, ChatGPT login. Through OpenRouter it identifies itself by name in your usage dashboard.
A chain is judged clause by clause
git status && rm -rf / is two decisions, not one. An allow rule you wrote for git status never covers whatever rides in beside it on the same line.
Plain files, all the way down
Skills and agents are markdown. Sessions are append-only JSONL — resume with a flag, fork by copying a file. Nothing you build is locked into haxford.
Speaks MCP
Any stdio MCP server drops its tools alongside the built-ins — same permission engine, same rules, same audit trail. No walled garden.
One binary
No daemon, no account, no service to keep alive. Install with curl, upgrade with haxford update, and nothing is left running when the terminal closes.
what it actually does
Reads a file. Understands it. Tells you.
This is a real haxford session, not a mockup — one prompt in, streamed straight to the terminal. No dashboard, no browser tab, no job queue to poll.
Everything below is exactly this shape: a prompt, tool calls as they're needed, an answer that shows its work.
A real turn, unedited.
teach it once
Teach it once. It remembers forever.
A skill is a folder with one file: a one-line description and a body. haxford indexes the description at startup — a line per skill, nothing more — and only reads the body when the model decides it's actually relevant. Teach it your release process once and it's there for every session after, in every project, for free until the moment it's used.
Extensions (commands, tools, lifecycle hooks) and themes work the same way: plain files under ~/.haxford, no build step, no package manager. Edit one, run /reload, it's live. Ask haxford to build you a skill and it can write the file that becomes one — the agent extends itself.
$ cat ~/.haxford/skills/release/SKILL.md---name: releasedescription: Cut a release — version bump, changelog, tag, GitHub release.--- # Cutting a release 1. Bump `version` in package.json.2. Update CHANGELOG.md with everything since the last tag.3. `git tag -a v$VERSION` and push. $ haxfordhaxford v0.3.0self-extensible - see ~/.haxford/EXTENDING.md · skills · extensionsA real SKILL.md — this exact frontmatter shape, indexed at startup.
reviews before it runs
A command chain is judged clause by clause.
git status && rm -rf / is not one decision — it's two. haxford splits a shell command on every &&, ;, and |, and judges each piece on its own merits. git status is read-only and runs without a prompt; rm -rf / still stops for a decision, every single time — even if you've already told haxford to always allow git status.
That's the whole model: an allow rule for one command is never a blank cheque for whatever rides in beside it on the same line. Nothing mutates — no write, no edit, no shell command — without a decision, yours or a rule you wrote.
△ edit file · writeFix the retry loop so backoff resets on successsrc/update.ts args: { "filePath": "src/update.ts", "oldString": "…", … } [a] allow once [s] always (this session) [d] denyesc = denyThe permission prompt, verbatim — yellow border, three decisions, no defaults.
your keys, your call
Use the model you already pay for.
Anthropic, OpenAI, OpenRouter, Ollama, Z.AI, Moonshot, opencode, or ChatGPT login (Codex) — name any of them as provider/model and haxford resolves the key from config, env, or your existing auth store. No haxford account, no proxy sitting between you and the provider, no markup.
Route through OpenRouter specifically and haxford identifies itself on every request — it shows up as its own app, by name, in YOUR OpenRouter usage dashboard. Your spend, attributed and auditable, not lost in someone else's aggregate.
$ haxford › /model providers anthropic · openai · openrouter · ollama … › anthropic/claude-sonnet-5 200k ctx · $0.15/M · $0.60/M deepseek/deepseek-chat-v3.1 :free moonshot/kimi-k2 200k ctx · $0.15/M · $0.60/M enter select · esc cancelThe /model picker — ctx and per-million pricing rendered right of every model.
never stuck waiting
Keep typing. It catches up.
Most agents make you wait: one turn, then silence until it's done. haxford's composer never locks — type the next thing while it's mid-tool-call and it queues, FIFO, shown as dim lines stacked right above the input so you always know what's waiting and in what order it'll run.
Changed your mind? Up-arrow on an empty composer pulls the most recently queued line back out for editing before it's ever sent. Everything flushes the moment the current turn goes idle — an abort still flushes what's behind it, so interrupting one thing never costs you the next.
⏎ also check the tests ⏎ and update the README +2 more queued──────────────────────────────────────────────── › queued until the current run finishes…────────────────────────────────────────────────Exactly what the composer shows — real strings, not paraphrased.
sessions that resume
Close the terminal. The work is still there.
Every session is append-only JSONL — one line per message snapshot, a later line with the same id superseding an earlier one on load. No rewrite, no migration, no server holding your state: the file on disk is the state.
haxford -c resumes the most recent session for this directory; /sessions opens a picker for any of them. Forking a conversation is copying a file — branch an idea, try two approaches, keep both.
$ haxford › /sessions › refactor update.ts checksum flow 5m ago fix musl release matrix 3h ago spike: bottom-pin the footer 2d ago enter resume · esc cancelThe session picker — every conversation on disk, one flag away.
personas, not plugins
A reviewer. A planner. Each one just a markdown file.
.haxford/agents/reviewer.md can pin its own model, drop the permission mode to plan (read-only), and restrict its tools to read, glob, grep — then haxford --agent reviewer runs with all of that. No code, no registration step, no plugin API to learn.
Project agents shadow global ones with the same name, so a repo can ship its own reviewer or planner right alongside the code it works on. The listing below is the actual file haxford writes to ~/.haxford/agents on first run.
$ cat ~/.haxford/agents/reviewer.md---description: Review code for correctness and quality. Read-only.mode: plantools: read, glob, grep--- You are a rigorous code reviewer. For each finding report:- Location as file_path:line so it can be clicked.- Severity: blocker, concern, or nit.- Why, in one or two sentences. $ haxford --agent reviewerShipped on first run — not a hypothetical example.
open standard, not a walled garden
Connect the tools you already run.
haxford speaks MCP over stdio: name a server in .haxford/mcp.json and its tools sit alongside the built-ins — same permission engine, same allow/ask/deny rules, same audit trail. Nothing haxford-specific to learn on the server side; any MCP server works, because MCP is the whole interface.
No proprietary server, no marketplace to browse. Point it at the open-source ecosystem, wire up something internal, or write your own in an afternoon.
$ cat .haxford/mcp.json{ "mcpServers": { "postgres": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-postgres", "$DATABASE_URL"] } }}The real config shape — one JSON file, nothing haxford-specific.
honest about the limits
What we didn't build.
haxford is one binary by design. The things it doesn't do aren't gaps waiting to be filled — they're the shape of the tool. Here they are, plainly.
No hosted backend
why
There's no haxford account, no server relaying your requests, nothing to sign up for. Your keys talk to your providers directly — haxford is a binary on your machine, not a service it's phoning home to.
No image input to the model
why
You can paste an image and it renders in your transcript, but only text parts reach the model today. Screenshots and diagrams aren't on the wire yet.
No sandboxing
why
haxford runs with the permissions of the user and process that launched it. The permission engine gates actions — it is not a filesystem or OS sandbox, and it never pretends to be.
No background services
why
No daemon, no language server, nothing kept alive between runs. Close the terminal and it's gone; open it again and the session resumes from disk.
No truecolor
why
The TUI renders ANSI 16-color output and borrows your terminal's own palette. It looks like your theme, not a custom one imposed on you.
get started
Install in under a minute.
Requires Bun ≥ 1.2 and one provider key. One command upgrades you later — no package manager to babysit, no version drift between machines.
curl -fsSL https://haxford.dev/install.sh | bash
# Re-run anytime to upgrade: haxford updatequickstart
$ curl -fsSL https://haxford.dev/install.sh | bashone-line install with checksum verification$ haxfordopen the TUI in this directory$ haxford "explain src/index.ts"start with an initial prompt$ haxford -cresume the most recent session here$ haxford --agent revieweruse a named agent from .haxford/agents/$ haxford -m openrouter/anthropic/claude-sonnet-5pick a model for this run$ haxford updatecheck and install the latest prebuilt binaryslash commands
Ten built-in.
Type / in the composer for autocomplete. Move with ↑/↓, accept with Enter.
/helpShow in-app command and keybinding help/modelOpen the model picker with live pricing/connectConnect or re-key a provider/sessionsOpen the session picker for this project/reloadReload skills, extensions, and themes from ~/.haxford/compactCompact the conversation now/initAnalyze the codebase and create AGENTS.md/modeSwitch permission mode · cycles with tab/clearStart a fresh session/exitQuit haxfordGitHub
Source, issues, and the full docs. Clone it, build it, break it.
Documentation
Getting started, providers, permissions, commands, sessions, architecture.