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 update
$ curl -fsSL https://haxford.dev/install.sh | bash
requires Bun ≥ 1.2·eight providers, your keys·keeps working while you type
scroll to continue

why 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: release
description: 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.
 
$ haxford
haxford v0.3.0
self-extensible - see ~/.haxford/EXTENDING.md · skills · extensions

A 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 · write
Fix the retry loop so backoff resets on success
src/update.ts
 
args:
{ "filePath": "src/update.ts", "oldString": "…", … }
 
[a] allow once [s] always (this session) [d] deny
esc = deny

The 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 cancel

The /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 cancel

The 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: plan
tools: 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 reviewer

Shipped 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 update

quickstart

$ 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 binary

slash 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 haxford

GitHub

Source, issues, and the full docs. Clone it, build it, break it.

Documentation

Getting started, providers, permissions, commands, sessions, architecture.