OOpenHarness

OpenHarnessOpen-source LLM terminal CLI

9623
Views33
Profile updated2026-08-18Source observed2026-09-21LanguageAI English · Bilingual

Overview

README
README.zh-CN.md
Language
zh-cn
hash
c5dc5e64599a
Original
GitHub
README
README.zh-CN.md
Language
en
Translation
AI translation
Generated at
2026-08-18 17:52
hash
c5dc5e64599a
Original
GitHub
README
README.md
Language
en
Original
GitHub
Quick take

Open source local terminal cli with any LLM

Adoption threshold
Low, requires environment setup
Supported platforms
CLI, Node.js, Python
Deployment
Self-hosted
Access method
GitHub / source / Docs

openHarness logo

OpenHarness

        ___
       /   \
      (     )        ___  ___  ___ _  _ _  _   _ ___ _  _ ___ ___ ___
       `~w~`        / _ \| _ \| __| \| | || | /_\ | _ \ \| | __/ __/ __|
       (( ))       | (_) |  _/| _|| .` | __ |/ _ \|   / .` | _|\__ \__ \
        ))((        \___/|_|  |___|_|\_|_||_/_/ \_\_|_\_|\_|___|___/___/
       ((  ))
        `--`

An AI coding assistant in your terminal. Works with any LLM — free local models or any cloud API.

OpenHarness demo

npm version npm downloads license tests tools Node.js 18+ TypeScript GitHub stars GitHub issues PRs Welcome

English | 简体中文


Table of Contents


Quick Start

npm install -g @zhijiewang/openharness
oh

That's all it takes. OpenHarness auto-detects Ollama and starts chatting. No API key needed.

Python SDK: We also provide an official Python SDK for driving oh from Python programs (notebooks, batch scripts, ML pipelines). After npm installation, install via pip install openharness-sdk (distributed on PyPI as openharness-sdk since the un-suffixed name was taken), then from openharness import query. See `python/README.md`.

TypeScript SDK: Similarly, an official TypeScript SDK for driving oh from Node.js (VS Code extensions, Electron apps, build scripts, etc.): use @zhijiewang/openharness-sdk — install via npm install @zhijiewang/openharness-sdk, then import { query, OpenHarnessClient, tool } from "@zhijiewang/openharness-sdk". Feature-parity with the Python SDK (streaming events, stateful sessions, custom tools, permission callbacks, session resumption). See `packages/sdk/README.md`.

oh init                               # 交互式安装向导(模型提供商 + 电子宠物)
oh                                    # 自动检测本地模型
oh --model ollama/qwen2.5:7b         # 指定模型
oh --model gpt-4o                     # 云端模型(需要 OPENAI_API_KEY)
oh --trust                            # 自动批准所有工具调用
oh --auto                             # 自动批准,但阻止危险的 bash 命令
oh -p "fix the tests" --trust         # 无头模式(单次提示后退出)
oh run "review code" --json           # 用于 CI/CD 的 JSON 输出

In-session commands:

/rewind                               # 撤销最近一次 AI 文件变更(恢复检查点)
/roles                                # 列出所有代理专长
/vim                                  # 切换 vim 模式
Ctrl+O                                # 将历史记录刷入终端滚动缓冲区以便查阅

Why OpenHarness?

Most AI coding assistants are locked to a single model provider or cost $20+/month. OpenHarness works with any LLM — run free local models with Ollama, or connect to any cloud API. Every AI edit is automatically committed to git and can be reverted with /undo.

Terminal Interface

OpenHarness uses a sequential terminal renderer inspired by Ink/Claude Code's default mode. Completed messages flush into the native scroll buffer (scrollable), while live regions (streaming output, loading animations, input box) redraw in-place via relative cursor movement.

Keybindings

KeyAction
EnterSubmit prompt
Alt+EnterInsert newline (multi-line input)
/ Browse input history
Ctrl+CCancel current request / exit
Ctrl+A / Ctrl+EJump to start / end of input box
Ctrl+OExpand / collapse thinking blocks
Ctrl+KExpand / collapse code blocks in messages
TabAutocomplete slash commands / file paths / cycle through tool outputs
/vimToggle Vim mode (normal/insert)

Scrolling is handled by the terminal's native scrollbar. Completed messages enter the terminal scroll buffer. Use the terminal's built-in search (e.g. Ctrl+Shift+F in VS Code) to search conversation history.

Features

  • Markdown rendering — headings, code blocks, bold, italic, lists, tables, blockquotes, links
  • Syntax highlighting — keywords, strings, comments, numbers, types (20+ languages: JS/TS/Python/Rust/Go, etc.)
  • Collapsible code blocks — blocks over 8 lines auto-collapse; press Ctrl+K to expand all
  • Collapsible thinking blocks — thinking blocks collapse to a one-line summary when done; press Ctrl+O to expand
  • Streaming loading animation — stage-labeled indicators (Thinking, Running <Tool>, Calling <server>:<tool>, Running N tools) with color transitions (magenta after 30s → yellow, red after 60s)
  • Tool call display — argument preview, real-time streaming output, result summary (line count, duration), expand/collapse with Tab. Tool names are color-coded by category (read: cyan, modify: yellow, execute: magenta, MCP: green)
  • Rich tool output — JSON files render as a colorful static tree (3-level collapse depth, line truncation); Markdown files render with full styling (headings, code blocks, tables), not plain line-by-line splitting. The renderer dispatches via the outputType field (FileReadTool / WebFetchTool are labeled); unlabeled tools fall back to a heuristic path
  • Nested tool calls — when an Agent or ParallelAgents spawns inner tool calls (Read, Bash, Edit), sub-calls are indented beneath the parent that spawned them. ParallelAgents also shows a Task wrapper line for each task, grouping sub-calls by task rather than flattening them under the merged parent. 3-level indentation cap, shows … (N more level) collapse marker when exceeded
  • Multi-line input wrap indicator — every non-final line of multi-line input ends with a dim continuation character, making line wrapping visually clear
  • Permission prompts — bordered prompt box with risk-level coloring, prominent Yes/No/Diff keys, inline diff with syntax highlighting
  • Status bar — shows model name, token count, cost, context usage bar (customizable via config)
  • Context warning — yellow warning when context window exceeds 75%
  • Native terminal scrollbar — completed messages enter the scroll buffer; use the terminal's scrollbar and search
  • Multi-line inputAlt+Enter inserts a newline; auto-detected and newline-inserted on paste
  • Autocomplete — slash commands and file paths (with descriptions); cycle through with Tab
  • File path completion — Tab completes paths, marked with [dir]/[file]
  • Session browser — use /browse to interactively browse and resume historical sessions
  • Desktop pet — animated Cybergotchi in the footer (toggle with /companion off|on)

Themes

oh --light                    # 适用于明亮终端的浅色主题
/theme light                  # 会话中切换(自动保存)
/theme dark                   # 切回深色

Theme preferences are saved to .oh/config.yaml and persist across sessions.

Custom Status Bar

Customize the status bar format in .oh/config.yaml:

statusLineFormat: '{model} │ {tokens} │ {cost} │ {ctx}'

Available variables: {model}, {tokens} (input↑ output↓), {cost} ($X.XXXX), {ctx} (context usage bar). Empty segments auto-collapse.

Tools (44)

ToolRiskDescription
Core
BashHighExecute shell commands with real-time streaming output (AST safety analysis)
PowerShellHighExecute PowerShell commands (Windows native scripts)
ReadLowRead files by line range, supports PDF
ImageReadLowRead images/PDFs for multimodal analysis
WriteMediumCreate or overwrite files
EditMediumSearch and replace edits
MultiEditMediumAtomic multi-file edits (all-or-nothing)
GlobLowFind files by pattern
GrepLowRegex content search with context lines
LSLowList directory contents and sizes
Web
WebFetchMediumFetch URL content (SSRF protection)
WebSearchMediumWeb search
ExaSearchMediumNeural search via Exa (requires EXA_API_KEY)
RemoteTriggerHighSend HTTP requests to webhooks/APIs
Tasks
TaskCreateLowCreate structured tasks
TaskUpdateLowUpdate task status
TaskListLowList all tasks
TaskGetLowGet task details
TaskStopLowStop a running task
TaskOutputLowGet task output
TodoWriteLowManage session-level todo list (Claude Code compatible)
Agents
AgentMediumSpawn a sub-agent (with optional role)
ParallelAgentMediumDispatch multiple agents with DAG dependencies
SendMessageLowPeer-to-peer messaging between agents
AskUserLowAsk the user a question (with options)
Scheduling
CronCreateMediumCreate scheduled tasks
CronDeleteMediumDelete scheduled tasks
CronListLowList all scheduled tasks
ScheduleWakeupLowAdaptively schedule the next trigger in /loop (cache-aware)
Planning
EnterPlanModeLowEnter structured planning mode
ExitPlanModeLowExit planning mode
Pipeline
PipelineMediumExecute a sequence of sub-tasks, passing each step's output as the next step's input
Code Intelligence
DiagnosticsLowLSP-based code diagnostics
NotebookEditMediumEdit Jupyter notebooks
Memory & Discovery
MemoryLowSave / list / search persistent memory
SkillLowInvoke skills under .oh/skills/
ToolSearchLowFind tools by description
SessionSearchLowSearch historical sessions for relevant context
MCP
ListMcpResourcesLowList resources on connected MCP servers
ReadMcpResourceLowRead a specific MCP resource by URI
Git Worktrees
EnterWorktreeMediumCreate an isolated git worktree
ExitWorktreeMediumRemove a git worktree
Processes
KillProcessHighStop a process by PID or name
MonitorMediumRun a command in the background, streaming each line of output back to the agent

Low-risk read-only tools auto-approve. Medium/high-risk tools prompt in ask mode. Use --trust or --auto to skip prompts.

Slash Commands

OH registers 80+ slash commands; only the most commonly used are listed below. Run /help in-session for the full list. Aliases: /q quit, /h help, /c commit, /m model, /s status.

Session:

CommandDescription
/clearClear conversation history
/compactCompact conversation to free up context
/exportExport conversation as markdown
/copy [n]Copy the Nth-to-last assistant reply to system clipboard
/history [n]List recent sessions; /history search <term> to search
/browseInteractive session browser with preview
/resume <id>Resume a saved session
/forkClone the current session

Git:

CommandDescription
/diffShow uncommitted git changes
/undoUndo the last AI commit
/commit [msg]Create a git commit
/logShow recent git commits

Info:

CommandDescription
/helpShow all available commands (by category)
/costShow session cost and token usage
/statusShow model, mode, git branch, MCP servers
/configShow configuration
/filesList files in context
/model <name>Switch model in session
/memoryView and search memory
/doctorRun diagnostic health check
/hooksList loaded hooks by event
/reload-pluginsHot-reload plugins, skills, hooks, and MCP server connections without restarting the session

Settings:

CommandDescription
`/theme darklight`Switch theme (auto-saved to config)
/vimToggle Vim mode
`/companion offon`Toggle desktop pet visibility
/keysShow keyboard shortcuts
/keybindingsOpen ~/.oh/keybindings.json in $EDITOR (created on first run)

AI:

CommandDescription
/plan <task>Enter planning mode
/reviewReview recent code changes
/summarizeSummarize the current conversation
/recapOne-line recap of the session (lighter than /summarize)

Pet:

CommandDescription
/cybergotchiFeed, pet, rest, status, rename, or reset the digital pet

Permission Modes

Controls how aggressively OpenHarness auto-approves tool calls:

ModeFlagBehavior
ask--permission-mode askPrompt for medium/high-risk operations (default)
trust--trustAuto-approve everything
deny--denyOnly allow low-risk read-only operations
acceptEdits--permission-mode acceptEditsAuto-approve file edits, still ask for Bash/WebFetch/Agent
plan--permission-mode planRead-only mode — blocks all write operations
auto--autoAuto-approve all operations, block dangerous bash (via AST analysis)
bypassPermissions--permission-mode bypassPermissionsUnconditionally approve everything (CI only)

Bash commands are analyzed by a lightweight AST parser that detects destructive patterns (rm -rf, git push --force, curl | bash, etc.) and adjusts risk level accordingly.

Set permanently in .oh/config.yaml: permissionMode: 'acceptEdits'

Hooks

Run shell scripts automatically on key session events by adding a hooks block in .oh/config.yaml:

hooks:
  - event: sessionStart
    command: "echo 'Session started' >> ~/.oh/session.log"

  - event: preToolUse
    command: "scripts/check-tool.sh"
    match: Bash   # 可选:仅对该工具名触发

  - event: postToolUse
    command: "scripts/after-tool.sh"

  - event: sessionEnd
    command: "scripts/cleanup.sh"

Event types (27 total — consistent with Claude Code stable):

EventTriggerCan Block
sessionStartSession start
sessionEndSession end
turnStartTop-level agent turn starts (after user prompt is accepted)
turnStopTop-level agent turn ends (corresponds to Claude Code's Stop)
userPromptSubmitBefore user prompt reaches LLMYes — decision: deny
userPromptExpansionWhen a slash command expands into a model prompt (for audit tracking)
preToolUseBefore a tool is calledYes — exit code 1 / decision: deny
postToolUseAfter a tool succeeds
postToolUseFailureWhen a tool throws or returns isError: true
postToolBatchAfter all tool calls in a turn complete, before the next model call
permissionRequestWhen a tool needs authorization (between preToolUse and prompting)Yes — `decision: allowdenyask`
permissionDeniedWhen a tool call is denied (by hook / user / headless / policy)
fileChangedAfter a tool modifies a file
cwdChangedAfter the working directory changes
subagentStartWhen a sub-agent is spawned
subagentStopWhen a sub-agent completes
preCompactBefore conversation compaction
postCompactAfter conversation compaction
configChangeWhen .oh/config.yaml is modified during a session
notificationWhen a notification is dispatched
taskCreatedAfter TaskCreate persists a new task
taskCompletedWhen TaskUpdate transitions a task to completed
worktreeCreateWhen EnterWorktreeTool creates an isolated git worktree
worktreeRemoveWhen ExitWorktreeTool removes a git worktree
elicitationWhen an MCP server requests user input via elicitation/createYes — `decision: allowdeny`
elicitationResultAfter an elicitation decision is made (for audit tracking)
instructionsLoadedAfter loadRulesAsPrompt reconstructs the system prompt and loads rules

Globally disable hook execution (while keeping definitions on disk for audit) with disableAllHooks: true in .oh/config.yaml.

View live: run /hooks in-session to see currently loaded hooks grouped by event.

Environment variables (available to hook scripts):

VariableDescription
OH_EVENTEvent type (sessionStart, preToolUse, etc.)
OH_TOOL_NAMETool being called (tool events only)
OH_TOOL_ARGSJSON-encoded tool arguments (tool events only)
OH_TOOL_OUTPUTJSON-encoded tool output (postToolUse only)
OH_TOOL_INPUT_JSONComplete JSON tool input (tool events only)
OH_SESSION_ID / OH_MODEL / OH_PROVIDER / OH_PERMISSION_MODECurrent session context
OH_COST / OH_TOKENSCumulative cost and token count
OH_FILE_PATHChanged file path (fileChanged only)
OH_NEW_CWDNew working directory (cwdChanged only)
OH_TURN_NUMBER / OH_TURN_REASONTurn boundary context (turnStart / turnStop)

Use match to scope hooks to specific tool names (e.g. match: Bash fires only for the Bash tool). Supports substring, glob (e.g. Cron*), and /regex/flags matching.

Set jsonIO: true on a command hook to enable structured JSON I/O — the framework sends {event, ...context} on stdin and reads {decision, reason, hookSpecificOutput} from stdout. HTTP hooks accept the same response format. Full reference at docs/hooks.md.

Digital Pet Cybergotchi

OpenHarness comes with a Tamagotchi-style digital pet living in the sidebar. It reacts to your session in real-time — cheers for win streaks, complains about tool failures, gets hungry when ignored.

Hatch one:

oh init        # 安装向导包含电子宠物设置
/cybergotchi   # 或在会话中孵化

Commands:

/cybergotchi feed      # 饱食度 +30
/cybergotchi pet       # 快乐值 +20
/cybergotchi rest      # 精力值 +40
/cybergotchi status    # 显示需求与终生统计
/cybergotchi rename    # 起个新名字
/cybergotchi reset     # 换个物种重新开始

Needs decay over time (satiety fastest, happiness slowest). Feed and pet your pet on schedule to keep it happy.

Evolution — evolves based on lifetime milestones:

  • Stage 1 (✦ Magenta): 10 sessions or 50 commits
  • Stage 2 (★ Yellow + Crown): Complete 100 tasks, or 25 consecutive tool calls without failure

18 species to choose from: duck, cat, owl, penguin, rabbit, turtle, snail, octopus, axolotl, cactus, mushroom, mochi, capybara, goose, and more.

MCP Servers

Connect any MCP (Model Context Protocol) server by editing .oh/config.yaml:

provider: anthropic
model: claude-sonnet-4-6
permissionMode: ask
mcpServers:
  - name: filesystem
    command: npx
    args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
  - name: github
    command: npx
    args: ["-y", "@modelcontextprotocol/server-github"]
    env:
      GITHUB_PERSONAL_ACCESS_TOKEN: ghp_...

MCP tools appear alongside built-in tools. /status shows connected servers.

MCP server prompts as slash commands — servers implementing prompts/list (e.g. GitHub, Sentry, Linear) automatically expose their prompts as /<server>:<prompt> slash commands. Parameters use key=value syntax with optional quoting:

/github:summarize-pr repo=acme/widget pr=42
/sentry:triage-issue issue=ABC-123 severity="high priority"

Required parameters declared in a prompt template will error with usage info if missing (won't call the model). After modifying MCP config, run /reload-plugins to re-discover prompts.

Remote MCP Servers (HTTP / SSE)

mcpServers:
  - name: linear
    type: http
    url: https://mcp.linear.app/mcp
    headers:
      Authorization: "Bearer ${LINEAR_API_KEY}"

Full reference at docs/mcp-servers.md. OAuth 2.1 setup at docs/mcp-servers.md (auto-triggered on 401; also available via /mcp-login and /mcp-logout commands).

MCP Server Registry — browse and install from a curated directory:

/mcp-registry              # 浏览所有可用服务器
/mcp-registry github       # 显示指定服务器的安装配置
/mcp-registry database     # 按分类搜索

Categories: filesystem, git, database, api, search, productivity, dev-tools, ai.

Git Integration

In a git repository, OpenHarness auto-commits AI edits:

oh: Edit src/app.ts                    # 自动以 "oh:" 前缀提交
oh: Write tests/app.test.ts
  • Every AI file change is auto-committed
  • /undo reverts the last AI commit (OH commits only, won't touch yours)
  • /diff shows what changed
  • Your uncommitted files are safe — they're committed separately before any AI edit

Checkpoints & Rollback

Every file modification is checkpointed automatically before execution. If something goes wrong:

/rewind           # 从最近一次检查点恢复文件
/undo             # 回退最后一次 AI git 提交

Checkpoints are stored in .oh/checkpoints/, covering FileWrite, FileEdit, and Bash commands that modify files.

Verification Loop

After every file edit (Edit, Write, MultiEdit), OpenHarness automatically runs language-specific lint/type-check commands and feeds the results back into the agent's context. This is the single highest-impact harness engineering pattern — research shows automatic feedback delivers 2–3× quality improvement.

Auto-detection — if your project has tsconfig.json, .eslintrc*, pyproject.toml, go.mod, or Cargo.toml, verification rules are auto-identified. No configuration needed.

Custom rules (in .oh/config.yaml):

verification:
  enabled: true       # 默认:true(自动检测)
  mode: warn          # 'warn' 追加到输出;'block' 标记为错误
  rules:
    - extensions: [".ts", ".tsx"]
      lint: "npx tsc --noEmit 2>&1 | head -20"
      timeout: 15000
    - extensions: [".py"]
      lint: "ruff check {file} 2>&1 | head -10"

After each edit, the agent sees [Verification passed] or [Verification FAILED] with linter output, enabling self-correction.

Memory Consolidation

On session exit, OpenHarness auto-prunes stale memories via time decay:

  • Memories not accessed in 30+ days decay by 0.1 relevance every 30 days
  • Memories with relevance below 0.1 are permanently deleted
  • Updated relevance scores are written back to memory files

This keeps the memory system lean and relevant. Configure in .oh/config.yaml:

memory:
  consolidateOnExit: true   # 默认:true

Scheduled Tasks (Cron)

Create tasks that run automatically in the background:

# 通过斜杠命令
/cron list                    # 显示所有定时任务
/cron create "check-tests"    # 新建任务(交互式)
/cron delete <id>             # 删除任务

Schedule syntax: every 5m, every 2h, every 1d

The cron executor checks for due tasks every 60 seconds and runs them via sub-queries. Results are saved to ~/.oh/crons/history/.

Agent Roles

Dispatch specialized sub-agents to handle specific tasks:

/roles            # 列出所有可用角色
RoleDescriptionTools
code-reviewerFind bugs, security issues, style problemsRead-only
test-writerGenerate unit and integration testsRead + Write
docs-writerWrite documentation and commentsRead + Write + Edit
debuggerSystematically troubleshoot bugsRead-only + Bash
refactorerSimplify code without changing behaviorAll file tools + Bash
security-auditorOWASP, injection, secrets, CVE scanningRead-only + Bash
evaluatorAssess code quality and run tests (read-only)Read-only + Bash + Diagnostics
plannerDesign step-by-step implementation plansRead-only + Bash
architectAnalyze architecture and design structural changes (hands off to editor for implementation)Read-only
editorApply code changes per architect's plan, no re-planningRead + Edit + Write + MultiEdit + Bash
migratorSystematic codebase migration and upgradesAll file tools + Bash

Each role restricts sub-agents to only its recommended tools. You can also explicitly pass allowed_tools:

Agent({ subagent_type: 'evaluator', prompt: 'Run all tests and report results' })
Agent({ allowed_tools: ['Read', 'Grep'], prompt: 'Search for all TODO comments' })

Architect → Editor (Cost-saving pattern for multi-file changes)

For larger changes spanning multiple files, use the architecteditor two-pass workflow: architect (powerful model) reads the code and produces a structured plan; editor (lightweight model) mechanically applies the plan, no re-planning. When modelRouter is configured, OH automatically routes the architect role to the powerful tier and the editor role to the fast tier — compared to running a powerful model for both passes, multi-file changes typically save 30–50% cost.

Agent({ subagent_type: 'architect', prompt: 'Plan a migration from option A to option B across src/' })
# 把得到的方案再交给 editor:
Agent({ subagent_type: 'editor', prompt: '<paste plan>' })

Sub-agent Permission Isolation

Agent calls support a permission_mode parameter that can only tighten, not loosen the parent's permission mode. This is especially useful when the parent runs in trust but you want a review/audit sub-agent to remain read-only:

Agent({ subagent_type: 'code-reviewer', prompt: '...', permission_mode: 'plan' })
Agent({ subagent_type: 'security-auditor', prompt: '...', permission_mode: 'deny' })

If a requested mode is looser than the parent's (e.g. parent ask, sub-agent requests trust), the harness silently falls back to the parent's mode — the model can never use a sub-agent to bypass the user's approval gate.

Read-only roles default to plan mode. code-reviewer, evaluator, security-auditor, architect, and planner have permissionMode: 'plan' built in — they start as statically read-only under any parent permission, no need to pass permission_mode at the call site. Custom markdown agents defined in .oh/agents/*.md can also set permissionMode: plan (or permission-mode: plan) in the frontmatter as a default.

Headless Mode

Run a prompt once without the interactive UI — great for CI/CD and scripting:

# 推荐:chat 命令加 -p 参数
oh -p "fix the failing tests" --model ollama/llama3 --trust
oh -p "review src/query.ts" --auto --output-format json

# 替代:run 命令
oh run "fix the failing tests" --model ollama/llama3 --trust
oh run "add error handling to api.ts" --json    # JSON 输出

# 通过 stdin 输入
cat error.log | oh run "what's wrong here?"
git diff | oh run "review these changes"

# 会话总成本硬上限 —— 达到阈值时代理会以 reason: "budget_exceeded" 终止
oh run "review the diff" --model claude-sonnet-4-6 --max-budget-usd 0.50
oh session --model gpt-4o --max-budget-usd 5

Common CI / SDK CLI Flags

FlagEffect
--bareSkip optional startup work (project detection, plugins, memory, skills, MCP). System prompt retains only the tool-use baseline, faster startup for repos with large CLAUDE.md / RULES.md files.
--debug [category]Enable categorized debug logs. --debug enables all; --debug mcp,hooks enables only specified categories. Also reads OH_DEBUG env var.
--debug-file <path>Append debug logs to a file instead of stderr. Also reads OH_DEBUG_FILE.
--mcp-config <path>Load MCP servers from an external JSON file (merged on top of .oh/config.yaml).
--strict-mcp-configWith --mcp-config, completely ignore MCP servers in .oh/config.yaml.
--system-prompt-file <path> / --append-system-prompt-file <path>File path variants of --system-prompt / --append-system-prompt.
--no-session-persistenceSkip writing sessions to ~/.oh/sessions/, suitable for one-off CI runs.
--fallback-model <model>Fallback model for retriable errors from the primary model. Overrides .oh/config.yaml's fallbackProviders for this run.
--permission-prompt-tool <mcp_tool>Delegate tool authorization decisions to a specified MCP tool (e.g. mcp__myperm__check).
--init / --init-onlyRun interactive setup wizard before / instead of executing the command.

All flags work on both oh run and oh session. Full list at oh run --help and oh session --help.

Constrain Structured Output with --json-schema

Constrain model output to a JSON Schema. Useful for CI scripts that need to parse model output programmatically, avoiding regex heuristics:

oh -p "output {\"ok\": true, \"count\": 3} as JSON" \
  --trust \
  --json-schema '{"type":"object","properties":{"ok":{"type":"boolean"},"count":{"type":"integer"}},"required":["ok","count"]}'

Behavior:

  • stdout: single line of JSON on successful validation.
  • stderr: structured error on failure, with raw model output for debugging.
  • Exit codes: 0 validation passed, 2 schema itself invalid, 3 model output not valid JSON, 4 JSON doesn't match schema.

Supported keywords: type, properties, required, items, enum. For fuller validation, pipe to a dedicated validator.

GitHub Action for PR Review

OpenHarness ships a GitHub Action for automated code review:

# .github/workflows/ai-review.yml
on:
  pull_request:
    types: [opened, synchronize]

jobs:
  review:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - uses: ./.github/actions/review
        with:
          model: 'claude-sonnet-4-6'
          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}

Exit code 0 on success, 1 on failure.

Model Providers

# 本地(免费,无需 API key)
oh --model ollama/llama3
oh --model ollama/qwen2.5:7b

# 云端
OPENAI_API_KEY=sk-... oh --model gpt-4o
ANTHROPIC_API_KEY=sk-ant-... oh --model claude-sonnet-4-6
OPENROUTER_API_KEY=sk-or-... oh --model openrouter/meta-llama/llama-3-70b

# llama.cpp / GGUF
oh --model llamacpp/my-model

# LM Studio
oh --model lmstudio/my-model

llama.cpp / GGUF (Local, no Ollama needed)

Direct GGUF support via llama-server, avoiding Ollama's overhead. Usually faster for large models.

Prerequisites:

Start llama-server:

llama-server --model ./your-model.gguf --port 8080 --alias my-model

Configure via oh init:

  • Run oh init, select "llama.cpp / GGUF" when prompted

Or configure manually in .oh/config.yaml:

provider: llamacpp
model: my-model
baseUrl: http://localhost:8080
permissionMode: ask

Run:

oh
oh --model llamacpp/my-model
oh models                    # 列出可用模型

ACP (Agent Client Protocol)

Speak Agent Client Protocol over stdin/stdout, enabling ACP-compatible editors — Zed, JetBrains via ACP plugin, Cline, OpenCode, and more — to use OpenHarness as the underlying agent without writing a separate extension for each IDE:

oh acp                                          # 读取 .oh/config.yaml 的 provider/model
oh acp --provider anthropic --model claude-sonnet-4-6

Configure oh acp as the agent launch command in your editor's ACP integration. Session-update events (text chunks, tool calls, tool results) are automatically translated through OpenHarness's streaming protocol; permission confirmations currently still go through OpenHarness's own flow rather than ACP's requestPermission (noted for follow-up). @agentclientprotocol/sdk is an optionalDependency — if not installed, oh acp exits with a clear install prompt instead of silently failing.

Authentication (Auth)

Provider-agnostic credential management. Local LLMs (Ollama / llama.cpp / LM Studio) don't need auth — configure via oh init.

oh auth login [provider] [--key <value>]   # 存储某个提供商的 API key
oh auth logout [provider]                   # 清除已存储的 API key
oh auth status                              # 显示已存储的提供商及环境变量覆盖情况

[provider] defaults to the configured default provider. --key passes the key directly; otherwise OH prompts interactively in TTY mode and reads to EOF on piped input.

Scripted Key Resolution (apiKeyHelper)

Avoid writing keys to plaintext or encrypted storage by plugging in helper scripts (1Password, pass, vault, cloud key managers, etc.). The configured command is executed when fetching a key, with OH_PROVIDER as an env var; stdout (stripped of leading/trailing whitespace) is the key.

# .oh/config.yaml
apiKeyHelper: 'op read "op://Personal/Anthropic/key"'

Resolution priority: env var → encrypted storage → apiKeyHelper → legacy plaintext config.

Auto-Update

oh update                    # 检测安装方式(npm 全局 / npx / 本地克隆),打印对应的升级命令

Configuration Hierarchy

Config loads in layers (later ones override earlier ones):

  1. Global ~/.oh/config.yaml — default provider, model, theme shared across all projects
  2. Project .oh/config.yaml — project-level settings
  3. Local .oh/config.local.yaml — personal overrides (gitignored)

Set a default provider globally once:

# ~/.oh/config.yaml
provider: ollama
model: llama3
permissionMode: ask
theme: dark
language: zh-CN        # 可选 —— 模型会用该语言回复(代码、命令、路径保持原样)
outputStyle: default   # 可选 —— "default""explanatory""learning" 或自定义名

Then project config only needs to specify what's different:

# .oh/config.yaml
model: codellama   # 仅覆盖模型

Output Styles

Switch the agent's "personality" without modifying core instructions. Built-in styles:

  • default — standard software engineering assistant (no prefix)
  • explanatory — appends a ## Insights section after each task, explaining why the decision was made
  • learning — leaves 1–3 TODO(human) markers at key points, leaving the most learning-worthy code for you to write yourself

Custom styles are markdown files with YAML frontmatter. Save to .oh/output-styles/<name>.md (project-level) or ~/.oh/output-styles/<name>.md (user-level). Project-level > user-level > built-in.

---
name: code-review
description: 专注的代码审查模式
---

严格审查。对每个函数追问:逻辑是否正确?错误处理是否完整?有没有遗漏的边界情况?

Activate in .oh/config.yaml via outputStyle: code-review.

Project Rules

Create .oh/RULES.md in any repo (or run oh init):

- Always run tests after changes
- Use strict TypeScript
- Never commit to main directly

Rules auto-load into every session.

OpenHarness also auto-reads the following project instruction files (if present, loaded in parent-directory-first merge order):

  • CLAUDE.md (Anthropic convention) — includes hierarchical CLAUDE.md files from parent directories to project root, plus global ~/.claude/CLAUDE.md
  • AGENTS.md (agents.md cross-tool standard, adopted by Codex / Cursor / Copilot / Cline / Aider) — same parent-directory-first scan
  • CLAUDE.local.md (gitignored personal overrides)

If a repo is already configured with AGENTS.md for another agent, OpenHarness reads it directly — no migration needed.

Skills & Plugins

Skills

Skills are markdown files with YAML frontmatter that add reusable behavior:

---
name: deploy
description: Deploy the application to production
trigger: deploy
tools: [Bash, Read]
---

Run the deploy script with health checks...

Lookup locations (in order):

  1. .oh/skills/ — project-level skills
  2. ~/.oh/skills/ — global skills (available in all projects)

Skills auto-trigger when user messages contain trigger keywords; they can also be invoked explicitly via /skill deploy.

Plugins

Plugins are npm packages that bundle skills, hooks, and MCP servers:

{
  "name": "my-openharness-plugin",
  "version": "1.0.0",
  "skills": ["skills/deploy.md", "skills/review.md"],
  "hooks": {
    "sessionStart": "scripts/setup.sh"
  },
  "mcpServers": [
    { "name": "my-api", "command": "npx", "args": ["-y", "@my-org/mcp-server"] }
  ]
}

Name it openharness-plugin.json and place it at the npm package root. Install with npm install and OpenHarness auto-discovers it from node_modules/.

Evals

oh evals runs SWE-bench-Lite-compatible evals locally against any Provider, with enforced cost caps. Measures real bug fix performance, more meaningful than synthetic benchmarks.

# 用 5 美元总上限、2 路并发跑一个自定义 pack
oh evals run my-pack --max-cost-usd 5 --concurrency 2

# 只跑指定 instance
oh evals run my-pack --max-cost-usd 1 --instance django__django-11551

# 随机抽取 3 个
oh evals run my-pack --max-cost-usd 2 --sample 3

# 续跑因成本上限中断的运行
oh evals run my-pack --max-cost-usd 10 --resume 2026-05-05T14-30-00

# 列出已安装的 pack
oh evals list-packs

# 查看历史运行的汇总
oh evals show 2026-05-05T14-30-00

Output goes to ~/.oh/evals/runs/<run-id>/:

  • results.json — complete data per task: cost, turns, duration, tests_status, error messages.
  • predictions.json — directly submittable to the SWE-bench leaderboard https://www.swebench.com/。
  • transcripts/<instance_id>.jsonl — raw stream-json output from each task sub-process.

The pluggable pack protocol (pack.json + instances.jsonl + fixtures/<id>/) lets you write packs against any test suite. The scripts/build-evals-pack.mjs tool can bake a SWE-bench-Lite-compatible repo at a given base_commit into a fixture. See CONTRIBUTING.md.

The built-in swe-bench-lite-mini pack (10 curated instances, runs out of the box) ships in v2.40.2.

How It Works

graph LR
    User[用户输入] --> REPL[REPL 循环]
    REPL --> Query[查询引擎]
    Query --> Provider[LLM 提供商]
    Provider --> LLM[Ollama / OpenAI / Anthropic]
    LLM --> Tools[工具执行]
    Tools --> Permissions{权限检查}
    Permissions -->|批准| Execute[运行工具]
    Permissions -->|拒绝| Deny[拒绝并上报]
    Execute --> Response[流式响应]
    Response --> REPL

FAQ

Can I use it offline? Yes. Use Ollama with a local model — no network, no API key needed.

How much does it cost? Free. OpenHarness uses the MIT license. Cloud models require your own API key (BYOK), or use Ollama entirely free.

Is it secure? Yes. Seven permission modes control what tools can do. Bash commands are analyzed by an AST parser that blocks destructive patterns (rm -rf, curl | bash, etc.). Every file change is checkpointed and can be reverted via /rewind.

Can I use it in CI/CD? Yes. Run headless mode with oh -p "prompt" --auto, or use the built-in GitHub Action for PR review.

Does it support my language/framework? Yes. OpenHarness is language-agnostic — it reads, writes, and executes code in any language. Syntax highlighting covers 20+ languages.

How does it compare to Claude Code? ~95% feature parity for CLI use cases. Key advantages: works with any LLM (not just Anthropic), and uses the MIT license. See Why OpenHarness? above.

Installation

Requires Node.js 18+.

# 从 npm 安装
npm install -g @zhijiewang/openharness

# 从源码安装
git clone https://github.com/zhijiewong/openharness.git
cd openharness
npm install && npm install -g .

Development

npm install
npx tsx src/main.tsx              # 以开发模式运行
npx tsc --noEmit                  # 类型检查
npm test                          # 运行测试

Adding a Tool

Implement the Tool interface (with a Zod input schema) in src/tools/YourTool/index.ts, then register it in src/tools.ts.

Adding a Model Provider

Implement the Provider interface in src/providers/yourprovider.ts, then add a case in src/providers/index.ts.

Contributing

See CONTRIBUTING.md.

Community

Join the OpenHarness community to get help, share workflows, and discuss the future of AI coding assistants!

PlatformDetails & Links
🟣 DiscordJoin our Discord to chat with developers in real-time and get support.
🔵 Feishu / LarkScan the QR code below to join the community collaboration group:<br><br><img src="https://github.com/user-attachments/assets/54ade077-22ad-45d2-b38a-623464677d53" width="160" alt="Feishu group QR code">
🟢 WeChatScan the QR code below to join the WeChat group:<br><br><img src="https://github.com/user-attachments/assets/adcf291a-9ffe-4738-8608-f46a21e18db0" width="160" alt="WeChat group QR code">

License

MIT

zhijiewong

zhijiewong

GitHub author

Turning coffee into community-driven code ☕

2Articles0Followers33Views

Resource profile

ScenariosProgramming & DevelopmentResource typeCLI / command-line toolEntry / platform+2Platform informationLanguage / environment: Node.jsPythonDockerSource: GitHubPricingOpen source and freeHighlightsSelf-hostableOpen issues5 IssuesDefault branchmainLatest versionv2.39.0Primary languagezh-CN / enAvailabilityGlobalLicenseMITCollectionHarness / Agent Engineering