Harn is now a small, dependency-free terminal coding agent written with only Python standard-library modules. It talks to OpenRouter through the OpenAI-compatible chat-completions API and gives the model local tools for reading, writing, editing, searching, listing, and running shell commands.
harn and harn-stdlib are matched entry points. The importable runtime is
harn; harn_stdlib is a compatibility alias that re-exports the same public
API and runs the same CLI.
- Python 3.9 or later
- An OpenRouter API key in
OPENROUTER_API_KEYor~/.harn/harn.json
No package install is required when running from the repository.
Source install is also dependency-free at runtime and creates both console commands:
python -m pip install --no-deps .
harn --version
harn-stdlib --versionexport OPENROUTER_API_KEY="sk-or-v1-..."
python -m harn -p "List the important files in this repository"Equivalent stdlib alias:
python -m harn_stdlib -p "List the important files in this repository"Start the interactive stdlib TUI by running without a prompt, or force it with
--tui:
python -m harn
python -m harn --tui --cwd /path/to/projectInside the TUI, type a prompt and press Enter. Commands: /help, /clear,
/commands, /continue, /resume, /reset, /status, /trace, /tools,
/skill, /skills, and /quit. The input line supports Left/Right, Ctrl+A,
Ctrl+E, Ctrl+W, Ctrl+L, and Ctrl+O. The transcript scrolls with Up/Down and
PageUp/PageDown. While a response is generating, Esc or Ctrl+C cancels the
in-flight turn.
The TUI streams model output as OpenRouter chunks arrive. It shows reasoning
traces when OpenRouter returns reasoning or reasoning_details, plus tool
calls, bash command output, and edit diffs. These details are collapsed to five
lines by default; press Ctrl+O or run /trace to toggle full trace output.
Reasoning blocks use a high-contrast blue background, successful tool traces
use high-contrast green, and tool errors use high-contrast red. Bash results
with non-zero exit_code are treated as errors. UTF-8 input such as Cyrillic is
read through curses wide-character mode, and streamed trace blocks are scoped
per user turn so later replies stay below their question. Ctrl+O is read in
curses raw mode so terminal discard-output handling does not swallow it.
Single-newline reasoning fragments from the provider are normalized into spaces
so expanded trace output stays readable instead of showing one phrase per line.
TUI sessions are saved under ~/.harn/sessions/<session-id>/ with
metadata.json, state.json, events.jsonl, and transcript.log. Use
/resume to resume the latest previous session or /resume <session-id> for a
specific session. Use /continue to list recent sessions, then
/continue <number> or /continue <session-id> to load one. /clear clears
only the visible transcript; the append-only logs remain on disk.
/status includes approximate session context usage: message count, serialized
context characters, a dependency-free chars/4 token estimate, transcript entry
counts, and session file sizes.
Optional user config is loaded from ~/.harn/harn.json before defaults. CLI
flags win over environment variables, environment variables win over config,
and config wins over built-in defaults.
{
"api_key": "sk-or-v1-...",
"model": "deepseek-v4-flash",
"base_url": "https://openrouter.ai/api/v1",
"timeout": 120,
"temperature": 0.2,
"max_steps": 8,
"max_tokens": 4096,
"reasoning": "enabled"
}Use --config /path/to/harn.json for a different file or --no-config to
ignore the default config. openrouter_api_key, openrouter_base_url,
api_key_env, reasoning_effort, reasoning_max_tokens,
reasoning_enabled, and reasoning_exclude are also accepted config keys.
Harn's base system prompt includes coding-agent guidelines, tool discipline,
and a built-in Agent Instructions block for documentation, git hygiene,
progress tracking, and OPS.md maintenance. That means the documentation and
operations rules do not have to be repeated in every project AGENTS.md.
At runtime, the prompt is assembled in this order: base Harn instructions,
nearest project AGENTS.md when present, additional system prompt text, active
skills, then the current date and working directory.
Skills live under ~/.harn/skills/. The standard layout is one directory per
skill with a SKILL.md file:
~/.harn/skills/
code-review/
SKILL.md
docs/
SKILL.md
Enable skills from the CLI with --skill, or set "skills" and optionally
"skills_dir" in ~/.harn/harn.json:
python -m harn --skill code-review -p "Review this change"
python -m harn --list-skills{
"skills": ["code-review", "docs"],
"skills_dir": "~/.harn/skills"
}HARN_SKILLS accepts a comma- or space-separated skill list, and
HARN_SKILLS_DIR overrides the skill directory. In the TUI, use /skills to
show available and active skills, /skill <name>[,<name>...] to enable skills,
and /skill off to clear them. Active skill instructions are appended to the
system prompt for subsequent turns.
Reasoning can also be controlled with CLI flags:
python -m harn --reasoning enabled -p "Think visibly if the model supports it"
python -m harn --reasoning-max-tokens 2048 -p "Solve this carefully"The default model is deepseek-v4-flash. Override it with --model or
HARN_MODEL:
python -m harn --model deepseek-v4-flash -p "Read README.md and summarize it"Attach files with @file or --prompt-file:
python -m harn @README.md "What changed in this rewrite?"
python -m harn --prompt-file agent_eval_tests/prompts/DesignDoc.md -p "Name the invariants"Run in a specific working directory:
python -m harn --cwd /path/to/project -p "Create a short TODO.md"Disable tools for a pure model call:
python -m harn --no-tools -p "Answer without touching files"Original Harn CLI compatibility flags are accepted where they make sense in a
stdlib/OpenRouter runtime, including --print, --provider, --thinking,
--tools/-t, --no-tools/-nt, --no-builtin-tools/-nbt, --list-models,
--mode text|json, --offline, --tui, --skill, --no-skills, and
--no-context-files/-nc. Session, extension, theme, and export flags are parsed
for compatibility, but the stdlib runtime does not implement those subsystems.
The agent exposes these tools to the model:
| Tool | Purpose |
|---|---|
read |
Read a UTF-8 text file |
write |
Create, overwrite, or append a UTF-8 text file |
edit |
Replace exact text in a UTF-8 text file |
bash |
Run a bash command in the configured cwd |
grep |
Search files with a Python regular expression |
find |
Find files by shell-style glob pattern |
ls |
List a directory |
By default, tool paths are restricted to the configured cwd. Use
--allow-outside-cwd only when the prompt explicitly needs access outside the
working directory.
Static tests require only stdlib:
python -m unittest discover -s agent_eval_testsThe static suite verifies that python -m harn and python -m harn_stdlib
produce matching tool and version outputs, that the public APIs match, and
that original-Harn compatibility flags still parse.
Live OpenRouter evals use the copied AGENTS.md and DesignDoc.md prompts in
agent_eval_tests/prompts/ and are opt-in:
RUN_OPENROUTER_EVAL=1 OPENROUTER_API_KEY="sk-or-v1-..." python -m unittest discover -s agent_eval_testsThe API key is intentionally read from the environment and is not committed.
harn/ stdlib runtime and CLI
~/.harn/skills/ user skill directories with SKILL.md files
harn_stdlib/ compatibility alias for harn / harn-stdlib
agent_eval_tests/ static and live prompt eval tests
setup.cfg legacy setuptools metadata for both scripts
WIKI.md project feature summary
PROGRESS.md implemented and planned work
OPS.md operations runbook