{"id":48038596,"url":"https://github.com/zhijiewong/openharness","last_synced_at":"2026-05-05T08:00:35.222Z","repository":{"id":348388133,"uuid":"1197487195","full_name":"zhijiewong/openharness","owner":"zhijiewong","description":"Open source local terminal cli with any LLM","archived":false,"fork":false,"pushed_at":"2026-04-28T11:57:34.000Z","size":25131,"stargazers_count":88,"open_issues_count":3,"forks_count":19,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-04-28T13:33:14.256Z","etag":null,"topics":["ai","cli","coding-agent","llm","ollama","openai","terminal","typescript"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/@zhijiewang/openharness","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zhijiewong.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-31T16:10:00.000Z","updated_at":"2026-04-28T11:57:36.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/zhijiewong/openharness","commit_stats":null,"previous_names":["zhijiewong/openharness"],"tags_count":66,"template":false,"template_full_name":null,"purl":"pkg:github/zhijiewong/openharness","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zhijiewong%2Fopenharness","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zhijiewong%2Fopenharness/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zhijiewong%2Fopenharness/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zhijiewong%2Fopenharness/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zhijiewong","download_url":"https://codeload.github.com/zhijiewong/openharness/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zhijiewong%2Fopenharness/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32640538,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-04T10:08:07.713Z","status":"online","status_checked_at":"2026-05-05T02:00:06.033Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","cli","coding-agent","llm","ollama","openai","terminal","typescript"],"created_at":"2026-04-04T14:03:05.721Z","updated_at":"2026-05-05T08:00:35.202Z","avatar_url":"https://github.com/zhijiewong.png","language":"TypeScript","funding_links":[],"categories":["Terminal-native coding agents"],"sub_categories":["Open Source"],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"assets/logo-256.png\" alt=\"openHarness logo\" width=\"128\" /\u003e\n\u003c/p\u003e\n\n# OpenHarness\n\n```\n        ___\n       /   \\\n      (     )        ___  ___  ___ _  _ _  _   _ ___ _  _ ___ ___ ___\n       `~w~`        / _ \\| _ \\| __| \\| | || | /_\\ | _ \\ \\| | __/ __/ __|\n       (( ))       | (_) |  _/| _|| .` | __ |/ _ \\|   / .` | _|\\__ \\__ \\\n        ))((        \\___/|_|  |___|_|\\_|_||_/_/ \\_\\_|_\\_|\\_|___|___/___/\n       ((  ))\n        `--`\n```\n\nAI coding agent in your terminal. Works with any LLM -- free local models or cloud APIs.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"assets/openharness_v0.11.1_4.gif\" alt=\"OpenHarness demo\" width=\"800\" /\u003e\n\u003c/p\u003e\n\n[![npm version](https://img.shields.io/npm/v/@zhijiewang/openharness)](https://www.npmjs.com/package/@zhijiewang/openharness) [![npm downloads](https://img.shields.io/npm/dm/@zhijiewang/openharness)](https://www.npmjs.com/package/@zhijiewang/openharness) [![license](https://img.shields.io/npm/l/@zhijiewang/openharness)](LICENSE) ![tests](https://img.shields.io/badge/tests-1502-brightgreen) ![tools](https://img.shields.io/badge/tools-44-blue) ![Node.js 18+](https://img.shields.io/badge/node-18%2B-green) ![TypeScript](https://img.shields.io/badge/typescript-strict-blue) [![GitHub stars](https://img.shields.io/github/stars/zhijiewong/openharness)](https://github.com/zhijiewong/openharness) [![GitHub issues](https://img.shields.io/github/issues-raw/zhijiewong/openharness)](https://github.com/zhijiewong/openharness/issues) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen)](https://github.com/zhijiewong/openharness/pulls)\n\n**English** | [简体中文](README.zh-CN.md)\n\n---\n\n## Table of Contents\n\n- [Quick Start](#quick-start)\n- [Why OpenHarness?](#why-openharness)\n- [Terminal UI](#terminal-ui)\n- [Tools (44)](#tools-43)\n- [Slash Commands](#slash-commands)\n- [Permission Modes](#permission-modes)\n- [Hooks](#hooks)\n- [Checkpoints \u0026 Rewind](#checkpoints--rewind)\n- [Agent Roles](#agent-roles)\n- [Headless Mode \u0026 CI/CD](#headless-mode)\n- [Cybergotchi](#cybergotchi)\n- [MCP Servers](#mcp-servers)\n- [Providers](#providers)\n- [Auth](#auth)\n- [Update](#update)\n- [FAQ](#faq)\n- [Install](#install)\n- [Development](#development)\n- [Contributing](#contributing)\n- [Community](#community)\n\n---\n\n## Quick Start\n\n```bash\nnpm install -g @zhijiewang/openharness\noh\n```\n\nThat's it. OpenHarness auto-detects Ollama and starts chatting. No API key needed.\n\n**Python SDK:** there's also an official Python SDK for driving `oh` from Python programs (notebooks, batch scripts, ML pipelines). Install with `pip install openharness-sdk` after the npm install (the PyPI distribution is `openharness-sdk` because the unqualified name is taken), then `from openharness import query`. See [`python/README.md`](python/README.md).\n\n**TypeScript SDK:** drive `oh` from Node.js (VS Code extensions, Electron apps, build scripts) with `@zhijiewang/openharness-sdk` — `npm install @zhijiewang/openharness-sdk`, then `import { query, OpenHarnessClient, tool } from \"@zhijiewang/openharness-sdk\"`. Mirrors the Python SDK surface (streaming events, stateful sessions, custom tools, permission callback, session resume). See [`packages/sdk/README.md`](packages/sdk/README.md).\n\n```bash\noh init                               # interactive setup wizard (provider + cybergotchi)\noh                                    # auto-detect local model\noh --model ollama/qwen2.5:7b         # specific model\noh --model gpt-4o                     # cloud model (needs OPENAI_API_KEY)\noh --trust                            # auto-approve all tool calls\noh --auto                             # auto-approve, block dangerous bash\noh -p \"fix the tests\" --trust         # headless mode (single prompt, exit)\noh run \"review code\" --json           # CI/CD with JSON output\n```\n\n**In-session commands:**\n```\n/rewind                               # undo last AI file change (checkpoint restore)\n/roles                                # list agent specializations\n/vim                                  # toggle vim mode\nCtrl+O                                # flush transcript to scrollback for review\n```\n\n## Why OpenHarness?\n\nMost AI coding agents are locked to one provider or cost $20+/month. OpenHarness works with any LLM -- run it free with Ollama on your own machine, or connect to any cloud API. Every AI edit is git-committed and reversible with `/undo`.\n\n## Terminal UI\n\nOpenHarness features a sequential terminal renderer inspired by Ink/Claude Code's default mode. Completed messages flush to native scrollback (scrollable), while the live area (streaming, spinner, input) rewrites in-place using relative cursor movement.\n\n### Keybindings\n\n| Key | Action |\n|-----|--------|\n| `Enter` | Submit prompt |\n| `Alt+Enter` | Insert newline (multi-line input) |\n| `↑` / `↓` | Navigate input history |\n| `Ctrl+C` | Cancel current request / exit |\n| `Ctrl+A` / `Ctrl+E` | Jump to start / end of input |\n| `Ctrl+O` | Toggle thinking block expansion |\n| `Ctrl+K` | Toggle code block expansion in messages |\n| `Tab` | Autocomplete slash commands / file paths / cycle tool outputs |\n| `/vim` | Toggle Vim mode (normal/insert) |\n\nScrolling is handled by the terminal's native scrollbar. Completed messages flow into the terminal scrollback buffer. Use your terminal's search (e.g., `Ctrl+Shift+F` in VS Code) to search conversation history.\n\n### Features\n\n- **Markdown rendering** — headings, code blocks, bold, italic, lists, tables, blockquotes, links\n- **Syntax highlighting** — keywords, strings, comments, numbers, types (JS/TS/Python/Rust/Go and 20+ languages)\n- **Collapsible code blocks** — blocks over 8 lines auto-collapse; `Ctrl+K` to expand all\n- **Collapsible thinking** — thinking blocks collapse to a one-line summary after completion; `Ctrl+O` to expand\n- **Shimmer spinner** — animated indicator with stage label (`Thinking`, `Running \u003cTool\u003e`, `Calling \u003cserver\u003e:\u003ctool\u003e`, `Running N tools`) and color transitions (magenta → yellow at 30s → red at 60s)\n- **Tool call display** — args preview, live streaming output, result summaries (line counts, elapsed time), expand/collapse with `Tab`. Tool name color-coded by category (read tools cyan, mutating tools yellow, exec tools magenta, MCP tools green)\n- **Rich tool output** — JSON files render as a colored static tree (depth-3 collapse, line truncation); markdown files render with full styling (headings, code blocks, tables) instead of plain split-on-newline. Renderer dispatches via `outputType` field stamped by FileReadTool / WebFetchTool, with a heuristic fallback for unstamped tools\n- **Nested tool calls** — when `Agent` or `ParallelAgents` spawns inner tool calls (Read, Bash, Edit), the children render indented under their spawning parent. ParallelAgents shows per-task `Task` wrapper rows so child calls group by task instead of flat under the bundled parent. Depth-3 indent limit with `… (N more level)` collapse marker\n- **Multi-line input wrap glyph** — every non-last line of a multi-line input ends with a dim `↵` continuation marker so the wrap is visually obvious\n- **Permission prompts** — bordered box with risk coloring, bold colored **Y**es/**N**o/**D**iff keys, syntax-highlighted inline diffs\n- **Status line** — model name, token count, cost, context usage bar (customizable via config)\n- **Context warning** — yellow alert when context window exceeds 75%\n- **Native terminal scrollbar** — completed messages flow into scrollback; use your terminal's scrollbar and search\n- **Multi-line input** — `Alt+Enter` for newlines; paste detection auto-inserts newlines\n- **Autocomplete** — slash commands and file paths with descriptions; Tab to cycle\n- **File path autocomplete** — Tab-completes paths with `[dir]`/`[file]` indicators\n- **Session browser** — `/browse` to interactively browse and resume past sessions\n- **Companion mascot** — animated Cybergotchi in the footer (toggle with `/companion off|on`)\n\n### Themes\n\n```bash\noh --light                    # light theme for bright terminals\n/theme light                  # switch mid-session (saved automatically)\n/theme dark                   # switch back\n```\n\nTheme preference is saved to `.oh/config.yaml` and persists across sessions.\n\n### Custom Status Line\n\nCustomize the status bar format in `.oh/config.yaml`:\n\n```yaml\nstatusLineFormat: '{model} │ {tokens} │ {cost} │ {ctx}'\n```\n\nAvailable variables: `{model}`, `{tokens}` (input↑ output↓), `{cost}` ($X.XXXX), `{ctx}` (context usage bar). Empty sections are automatically collapsed.\n\n## Tools (44)\n\n| Tool | Risk | Description |\n|------|------|-------------|\n| **Core** | | |\n| Bash | high | Execute shell commands with live streaming output (AST safety analysis) |\n| PowerShell | high | Execute PowerShell commands (Windows-native scripting) |\n| Read | low | Read files with line ranges, PDF support |\n| ImageRead | low | Read images/PDFs for multimodal analysis |\n| Write | medium | Create or overwrite files |\n| Edit | medium | Search-and-replace edits |\n| MultiEdit | medium | Atomic multi-file edits (all succeed or none) |\n| Glob | low | Find files by pattern |\n| Grep | low | Regex content search with context lines |\n| LS | low | List directory contents with sizes |\n| **Web** | | |\n| WebFetch | medium | Fetch URL content (SSRF-protected) |\n| WebSearch | medium | Search the web |\n| ExaSearch | medium | Neural web search via Exa (requires `EXA_API_KEY`) |\n| RemoteTrigger | high | HTTP requests to webhooks/APIs |\n| **Tasks** | | |\n| TaskCreate | low | Create structured tasks |\n| TaskUpdate | low | Update task status |\n| TaskList | low | List all tasks |\n| TaskGet | low | Get task details |\n| TaskStop | low | Stop a running task |\n| TaskOutput | low | Get task output |\n| TodoWrite | low | Manage session task checklist (Claude Code-compatible) |\n| **Agents** | | |\n| Agent | medium | Spawn a sub-agent (with role specialization) |\n| ParallelAgent | medium | Dispatch multiple agents with DAG dependencies |\n| SendMessage | low | Agent-to-agent peer messaging |\n| AskUser | low | Ask user a question with options |\n| **Scheduling** | | |\n| CronCreate | medium | Schedule recurring tasks |\n| CronDelete | medium | Remove scheduled tasks |\n| CronList | low | List all scheduled tasks |\n| ScheduleWakeup | low | Self-pace the next /loop iteration (cache-aware) |\n| **Planning** | | |\n| EnterPlanMode | low | Enter structured planning mode |\n| ExitPlanMode | low | Exit planning mode |\n| **Pipelines** | | |\n| Pipeline | medium | Run a sequence of tasks with output passed between steps |\n| **Code Intelligence** | | |\n| Diagnostics | low | LSP-based code diagnostics |\n| NotebookEdit | medium | Edit Jupyter notebooks |\n| **Memory \u0026 Discovery** | | |\n| Memory | low | Save/list/search persistent memories |\n| Skill | low | Invoke a skill from .oh/skills/ |\n| ToolSearch | low | Find tools by description |\n| SessionSearch | low | Search prior sessions for relevant context |\n| **MCP** | | |\n| ListMcpResources | low | List resources from connected MCP servers |\n| ReadMcpResource | low | Read a specific MCP resource by URI |\n| **Git Worktrees** | | |\n| EnterWorktree | medium | Create isolated git worktree |\n| ExitWorktree | medium | Remove a git worktree |\n| **Process** | | |\n| KillProcess | high | Stop processes by PID or name |\n| Monitor | medium | Run a background command and stream each output line back to the agent |\n\nLow-risk read-only tools auto-approve. Medium and high risk tools require confirmation in `ask` mode. Use `--trust` or `--auto` to skip prompts.\n\n## Slash Commands\n\nOver 80 commands are registered. The most-used ones are grouped below; see `/help` in-session for the full list. Aliases: `/q` exit, `/h` help, `/c` commit, `/m` model, `/s` status.\n\n**Session:**\n| Command | Description |\n|---------|-------------|\n| `/clear` | Clear conversation history |\n| `/compact` | Compress conversation to free context |\n| `/export` | Export conversation to markdown |\n| `/copy [n]` | Copy the Nth-last assistant response to the system clipboard |\n| `/history [n]` | List recent sessions; `/history search \u003cterm\u003e` to search |\n| `/browse` | Interactive session browser with preview |\n| `/resume \u003cid\u003e` | Resume a saved session |\n| `/fork` | Fork current session |\n\n**Git:**\n| Command | Description |\n|---------|-------------|\n| `/diff` | Show uncommitted git changes |\n| `/undo` | Undo last AI commit |\n| `/commit [msg]` | Create a git commit |\n| `/log` | Show recent git commits |\n\n**Info:**\n| Command | Description |\n|---------|-------------|\n| `/help` | Show all available commands (categorized) |\n| `/cost` | Show session cost and token usage |\n| `/status` | Show model, mode, git branch, MCP servers |\n| `/config` | Show configuration |\n| `/files` | List files in context |\n| `/model \u003cname\u003e` | Switch model mid-session |\n| `/memory` | View and search memories |\n| `/doctor` | Run diagnostic health checks |\n| `/hooks` | List loaded hooks grouped by event |\n| `/reload-plugins` | Hot-reload plugins, skills, hooks, and MCP server connections without restarting the session |\n\n**Settings:**\n| Command | Description |\n|---------|-------------|\n| `/theme dark\\|light` | Switch theme (saved to config) |\n| `/vim` | Toggle Vim mode |\n| `/companion off\\|on` | Toggle companion visibility |\n| `/keys` | Show keyboard shortcuts |\n| `/keybindings` | Open `~/.oh/keybindings.json` in `$EDITOR` (creates a starter file if missing) |\n\n**AI:**\n| Command | Description |\n|---------|-------------|\n| `/plan \u003ctask\u003e` | Enter plan mode |\n| `/review` | Review recent code changes |\n| `/summarize` | Summarize the current conversation |\n| `/recap` | One-sentence recap of the session (lighter than `/summarize`) |\n\n**Pet:**\n| Command | Description |\n|---------|-------------|\n| `/cybergotchi` | Feed, pet, rest, status, rename, or reset your companion |\n\n## Permission Modes\n\nControl how aggressively OpenHarness auto-approves tool calls:\n\n| Mode | Flag | Behavior |\n|------|------|----------|\n| `ask` | `--permission-mode ask` | Prompt for medium/high risk operations (default) |\n| `trust` | `--trust` | Auto-approve everything |\n| `deny` | `--deny` | Only allow low-risk read-only operations |\n| `acceptEdits` | `--permission-mode acceptEdits` | Auto-approve file edits, ask for Bash/WebFetch/Agent |\n| `plan` | `--permission-mode plan` | Read-only mode — block all write operations |\n| `auto` | `--auto` | Auto-approve all, block dangerous bash (AST-analyzed) |\n| `bypassPermissions` | `--permission-mode bypassPermissions` | Approve everything unconditionally (CI only) |\n\nBash 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.\n\nSet permanently in `.oh/config.yaml`: `permissionMode: 'acceptEdits'`\n\n## Hooks\n\nRun shell scripts automatically at key session events by adding a `hooks` block to `.oh/config.yaml`:\n\n```yaml\nhooks:\n  - event: sessionStart\n    command: \"echo 'Session started' \u003e\u003e ~/.oh/session.log\"\n\n  - event: preToolUse\n    command: \"scripts/check-tool.sh\"\n    match: Bash   # optional: only trigger for this tool name\n\n  - event: postToolUse\n    command: \"scripts/after-tool.sh\"\n\n  - event: sessionEnd\n    command: \"scripts/cleanup.sh\"\n```\n\n**Event types** (27 total — matches Claude Code's stable surface):\n\n| Event | When it fires | Can block? |\n|-------|---------------|------------|\n| `sessionStart` | Session begins | — |\n| `sessionEnd` | Session ends | — |\n| `turnStart` | Top-level agent turn begins (after user prompt accepted) | — |\n| `turnStop` | Top-level agent turn ends (mirrors Claude Code's `Stop`) | — |\n| `userPromptSubmit` | Before user prompt reaches the LLM | yes — `decision: deny` |\n| `userPromptExpansion` | Slash command produces an expanded prompt (audit trail) | — |\n| `preToolUse` | Before each tool call | yes — exit code 1 / `decision: deny` |\n| `postToolUse` | After successful tool execution | — |\n| `postToolUseFailure` | After tool throws or returns `isError: true` | — |\n| `postToolBatch` | Once after a turn's full set of tool calls all resolve, before the next model call | — |\n| `permissionRequest` | When a tool needs approval (between `preToolUse` and the prompt) | yes — `decision: allow\\|deny\\|ask` |\n| `permissionDenied` | When a tool call is denied (hook / user / headless / policy) | — |\n| `fileChanged` | After a tool modifies a file | — |\n| `cwdChanged` | After working directory changes | — |\n| `subagentStart` | A sub-agent is spawned | — |\n| `subagentStop` | A sub-agent completes | — |\n| `preCompact` | Before conversation compaction | — |\n| `postCompact` | After conversation compaction | — |\n| `configChange` | `.oh/config.yaml` is modified during the session | — |\n| `notification` | A notification is dispatched | — |\n| `taskCreated` | `TaskCreate` persists a new task | — |\n| `taskCompleted` | `TaskUpdate` transitions a task to `completed` | — |\n| `worktreeCreate` | `EnterWorktreeTool` creates an isolated git worktree | — |\n| `worktreeRemove` | `ExitWorktreeTool` removes a git worktree | — |\n| `elicitation` | An MCP server requests user input via `elicitation/create` | yes — `decision: allow\\|deny` |\n| `elicitationResult` | After the elicitation response has been decided (audit trail) | — |\n| `instructionsLoaded` | `loadRulesAsPrompt` rebuilt the system prompt with rules in scope | — |\n\nSet `disableAllHooks: true` in `.oh/config.yaml` to globally disable hook execution while keeping definitions on disk for auditability.\n\nLive introspection: run `/hooks` in-session to see exactly which hooks are loaded, grouped by event.\n\n**Environment variables** available to hook scripts:\n\n| Variable | Description |\n|----------|-------------|\n| `OH_EVENT` | Event type (`sessionStart`, `preToolUse`, etc.) |\n| `OH_TOOL_NAME` | Name of the tool being called (tool events only) |\n| `OH_TOOL_ARGS` | JSON-encoded tool arguments (tool events only) |\n| `OH_TOOL_OUTPUT` | JSON-encoded tool output (`postToolUse` only) |\n| `OH_TOOL_INPUT_JSON` | Full JSON tool input (tool events only) |\n| `OH_SESSION_ID` / `OH_MODEL` / `OH_PROVIDER` / `OH_PERMISSION_MODE` | Current session context |\n| `OH_COST` / `OH_TOKENS` | Running cost and token totals |\n| `OH_FILE_PATH` | Path that changed (`fileChanged` only) |\n| `OH_NEW_CWD` | New working directory (`cwdChanged` only) |\n| `OH_TURN_NUMBER` / `OH_TURN_REASON` | Turn boundary context (`turnStart` / `turnStop`) |\n\nUse `match` to restrict a hook to a specific tool name (e.g., `match: Bash` only triggers for the Bash tool). Substring, glob (`Cron*`), and `/regex/flags` patterns are all supported.\n\nSet `jsonIO: true` on a `command` hook to opt into structured JSON I/O — the harness sends `{event, ...context}` on stdin and reads `{decision, reason, hookSpecificOutput}` from stdout. HTTP hooks accept the same response shape. See [docs/hooks.md](docs/hooks.md) for the full reference.\n\n## Cybergotchi\n\nOpenHarness ships with a Tamagotchi-style companion that lives in the side panel. It reacts to your session in real time — celebrating streaks, complaining when tools fail, and getting hungry if you ignore it.\n\n**Hatch one:**\n```\noh init        # wizard includes cybergotchi setup\n/cybergotchi   # or hatch mid-session\n```\n\n**Commands:**\n```\n/cybergotchi feed      # +30 hunger\n/cybergotchi pet       # +20 happiness\n/cybergotchi rest      # +40 energy\n/cybergotchi status    # show needs + lifetime stats\n/cybergotchi rename    # give it a new name\n/cybergotchi reset     # start over with a new species\n```\n\n**Needs** decay over time (hunger fastest, happiness slowest). Feed and pet your gotchi to keep it happy.\n\n**Evolution** — your gotchi evolves based on lifetime milestones:\n- Stage 1 (✦ magenta): 10 sessions or 50 commits\n- Stage 2 (★ yellow + crown): 100 tasks completed or a 25-tool streak\n\n**18 species** to choose from: duck, cat, owl, penguin, rabbit, turtle, snail, octopus, axolotl, cactus, mushroom, chonk, capybara, goose, and more.\n\n## MCP Servers\n\nConnect any MCP (Model Context Protocol) server by editing `.oh/config.yaml`:\n\n```yaml\nprovider: anthropic\nmodel: claude-sonnet-4-6\npermissionMode: ask\nmcpServers:\n  - name: filesystem\n    command: npx\n    args: [\"-y\", \"@modelcontextprotocol/server-filesystem\", \"/tmp\"]\n  - name: github\n    command: npx\n    args: [\"-y\", \"@modelcontextprotocol/server-github\"]\n    env:\n      GITHUB_PERSONAL_ACCESS_TOKEN: ghp_...\n```\n\nMCP tools appear alongside built-in tools. `/status` shows connected servers.\n\n**MCP server prompts as slash commands** — servers that expose `prompts/list` (e.g., GitHub, Sentry, Linear) get their prompts surfaced as `/\u003cserver\u003e:\u003cprompt\u003e` slash commands automatically. Arguments use a `key=value` syntax with quoting:\n\n```\n/github:summarize-pr repo=acme/widget pr=42\n/sentry:triage-issue issue=ABC-123 severity=\"high priority\"\n```\n\nRequired arguments declared by the prompt template surface a usage error if missing (no model call). Run `/reload-plugins` to re-discover prompts after editing your MCP config.\n\n### Remote MCP servers (HTTP / SSE)\n\n```yaml\nmcpServers:\n  - name: linear\n    type: http\n    url: https://mcp.linear.app/mcp\n    headers:\n      Authorization: \"Bearer ${LINEAR_API_KEY}\"\n```\n\nSee [docs/mcp-servers.md](docs/mcp-servers.md) for the full reference.\nSee [docs/mcp-servers.md](docs/mcp-servers.md#authentication) for OAuth 2.1 setup (auto-triggered on 401; `/mcp-login` and `/mcp-logout` commands available).\n\n**MCP Server Registry** — browse and install from a curated catalog:\n\n```\n/mcp-registry              # browse all available servers\n/mcp-registry github       # show install config for a specific server\n/mcp-registry database     # search by category\n```\n\nCategories: filesystem, git, database, api, search, productivity, dev-tools, ai.\n\n## Git Integration\n\nOpenHarness auto-commits AI edits in git repos:\n\n```\noh: Edit src/app.ts                    # auto-committed with \"oh:\" prefix\noh: Write tests/app.test.ts\n```\n\n- Every AI file change is committed automatically\n- `/undo` reverts the last AI commit (only OH commits, never yours)\n- `/diff` shows what changed\n- Your dirty files are safe — committed separately before AI edits\n\n## Checkpoints \u0026 Rewind\n\nEvery file modification is automatically checkpointed before execution. If something goes wrong:\n\n```\n/rewind           # restore files from the last checkpoint\n/undo             # revert the last AI git commit\n```\n\nCheckpoints are stored in `.oh/checkpoints/` and cover FileWrite, FileEdit, and Bash commands that modify files.\n\n## Verification Loops\n\nAfter every file edit (Edit, Write, MultiEdit), openHarness automatically runs language-appropriate lint/typecheck commands and feeds the results back into the agent context. This is the single highest-impact harness engineering pattern — research shows 2-3x quality improvement from automated feedback.\n\n**Auto-detection** — if your project has `tsconfig.json`, `.eslintrc*`, `pyproject.toml`, `go.mod`, or `Cargo.toml`, verification rules are detected automatically. No configuration needed.\n\n**Custom rules** via `.oh/config.yaml`:\n\n```yaml\nverification:\n  enabled: true       # default: true (auto-detect)\n  mode: warn          # 'warn' appends to output, 'block' marks as error\n  rules:\n    - extensions: [\".ts\", \".tsx\"]\n      lint: \"npx tsc --noEmit 2\u003e\u00261 | head -20\"\n      timeout: 15000\n    - extensions: [\".py\"]\n      lint: \"ruff check {file} 2\u003e\u00261 | head -10\"\n```\n\nThe agent sees `[Verification passed]` or `[Verification FAILED]` with the linter output after each edit, enabling self-correction.\n\n## Memory Consolidation\n\nOn session exit, openHarness automatically prunes stale memories using temporal decay:\n\n- Memories not accessed in 30+ days lose 0.1 relevance per 30-day period\n- Memories below 0.1 relevance are permanently deleted\n- Updated relevance scores are persisted to memory files\n\nThis keeps the memory system lean and relevant. Configure in `.oh/config.yaml`:\n\n```yaml\nmemory:\n  consolidateOnExit: true   # default: true\n```\n\n## Scheduled Tasks (Cron)\n\nCreate recurring tasks that run automatically in the background:\n\n```\n# Via slash commands\n/cron list                    # show all scheduled tasks\n/cron create \"check-tests\"    # create a new task (interactive)\n/cron delete \u003cid\u003e             # remove a task\n```\n\n**Schedule syntax:** `every 5m`, `every 2h`, `every 1d`\n\nThe cron executor checks every 60 seconds for due tasks and runs them via sub-queries. Results are stored in `~/.oh/crons/history/`.\n\n## Agent Roles\n\nDispatch specialized sub-agents for focused tasks:\n\n```\n/roles            # list all available roles\n```\n\n| Role | Description | Tools |\n|------|-------------|-------|\n| `code-reviewer` | Find bugs, security issues, style problems | Read-only |\n| `test-writer` | Generate unit and integration tests | Read + Write |\n| `docs-writer` | Write documentation and comments | Read + Write + Edit |\n| `debugger` | Systematic bug investigation | Read-only + Bash |\n| `refactorer` | Simplify code without changing behavior | All file tools + Bash |\n| `security-auditor` | OWASP, injection, secrets, CVE scanning | Read-only + Bash |\n| `evaluator` | Evaluate code quality and run tests (read-only) | Read-only + Bash + Diagnostics |\n| `planner` | Design step-by-step implementation plans | Read-only + Bash |\n| `architect` | Analyze architecture and design structural changes | Read-only |\n| `migrator` | Systematic codebase migrations and upgrades | All file tools + Bash |\n\nEach role restricts the sub-agent to only its suggested tools. You can also pass `allowed_tools` explicitly:\n\n```\nAgent({ subagent_type: 'evaluator', prompt: 'Run all tests and report results' })\nAgent({ allowed_tools: ['Read', 'Grep'], prompt: 'Search for all TODO comments' })\n```\n\n## Headless Mode\n\nRun a single prompt without interactive UI — perfect for CI/CD and scripting:\n\n```bash\n# Chat command with -p flag (recommended)\noh -p \"fix the failing tests\" --model ollama/llama3 --trust\noh -p \"review src/query.ts\" --auto --output-format json\n\n# Run command (alternative)\noh run \"fix the failing tests\" --model ollama/llama3 --trust\noh run \"add error handling to api.ts\" --json    # JSON output\n\n# Pipe stdin\ncat error.log | oh run \"what's wrong here?\"\ngit diff | oh run \"review these changes\"\n\n# Hard cap on session cost — agent halts at the threshold with reason: \"budget_exceeded\"\noh run \"review the diff\" --model claude-sonnet-4-6 --max-budget-usd 0.50\noh session --model gpt-4o --max-budget-usd 5\n```\n\n### CLI flags for CI / SDK use\n\n| Flag | Effect |\n|------|--------|\n| `--bare` | Skip optional startup work (project detection, plugins, memory, skills, MCP). System prompt is just the tool-use baseline. Faster startup on repos with many CLAUDE.md / RULES.md files. |\n| `--debug [categories]` | Enable categorized debug logs. `--debug` alone enables all; `--debug mcp,hooks` filters. Falls back to `OH_DEBUG` env var. |\n| `--debug-file \u003cpath\u003e` | Append debug lines to a file instead of stderr. Falls back to `OH_DEBUG_FILE`. |\n| `--mcp-config \u003cpath\u003e` | Load MCP servers from an external JSON file (in addition to `.oh/config.yaml`). |\n| `--strict-mcp-config` | With `--mcp-config`, ignore `.oh/config.yaml` MCP servers entirely. |\n| `--system-prompt-file \u003cpath\u003e` / `--append-system-prompt-file \u003cpath\u003e` | File-path variants of `--system-prompt` / `--append-system-prompt`. |\n| `--no-session-persistence` | Skip writing the session record to `~/.oh/sessions/` for ephemeral CI runs. |\n| `--fallback-model \u003cmodel\u003e` | Fallback used when the primary fails with a retriable error. REPLACES `.oh/config.yaml` `fallbackProviders` for this run. |\n| `--permission-prompt-tool \u003cmcp_tool\u003e` | Delegate tool-permission decisions to a configured MCP tool (e.g. `mcp__myperm__check`). |\n| `--init` / `--init-only` | Run the interactive setup wizard before / instead of the command. |\n\nAll flags work on both `oh run` and `oh session`. See `oh run --help` and `oh session --help` for the full surface.\n\n### Structured output with `--json-schema`\n\nConstrain the model's output to a JSON Schema. Useful for CI scripts that\nparse model output programmatically without regex heuristics:\n\n```bash\noh -p \"output {\\\"ok\\\": true, \\\"count\\\": 3} as JSON\" \\\n  --trust \\\n  --json-schema '{\"type\":\"object\",\"properties\":{\"ok\":{\"type\":\"boolean\"},\"count\":{\"type\":\"integer\"}},\"required\":[\"ok\",\"count\"]}'\n```\n\nBehavior:\n- stdout: the validated JSON (single line), only when it passes the schema.\n- stderr: structured errors on failure, plus the raw model output for debugging.\n- Exit codes: **0** valid, **2** malformed schema, **3** model output was not JSON, **4** JSON didn't match the schema.\n\nSupported keywords: `type`, `properties`, `required`, `items`, `enum`. For richer validation, pipe the output through a dedicated validator.\n\n### GitHub Action for PR Review\n\nOpenHarness includes a built-in GitHub Action for automated code review:\n\n```yaml\n# .github/workflows/ai-review.yml\non:\n  pull_request:\n    types: [opened, synchronize]\n\njobs:\n  review:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n      - uses: ./.github/actions/review\n        with:\n          model: 'claude-sonnet-4-6'\n          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}\n```\n\nExit code 0 on success, 1 on failure.\n\n## Providers\n\n```bash\n# Local (free, no API key needed)\noh --model ollama/llama3\noh --model ollama/qwen2.5:7b\n\n# Cloud\nOPENAI_API_KEY=sk-... oh --model gpt-4o\nANTHROPIC_API_KEY=sk-ant-... oh --model claude-sonnet-4-6\nOPENROUTER_API_KEY=sk-or-... oh --model openrouter/meta-llama/llama-3-70b\n\n# llama.cpp / GGUF\noh --model llamacpp/my-model\n\n# LM Studio\noh --model lmstudio/my-model\n```\n\n### llama.cpp / GGUF (local, no Ollama needed)\n\nFor direct GGUF support via `llama-server`, without the overhead of Ollama. Often faster for large models.\n\n**Prerequisites:**\n- Install llama.cpp: `brew install llama.cpp` or download from [github.com/ggml-org/llama.cpp](https://github.com/ggml-org/llama.cpp)\n- Download a GGUF model (e.g., from [HuggingFace](https://huggingface.co))\n\n**Start llama-server:**\n```bash\nllama-server --model ./your-model.gguf --port 8080 --alias my-model\n```\n\n**Configure via `oh init`:**\n- Run `oh init` and select \"llama.cpp / GGUF\" when prompted\n\n**Or configure manually** in `.oh/config.yaml`:\n```yaml\nprovider: llamacpp\nmodel: my-model\nbaseUrl: http://localhost:8080\npermissionMode: ask\n```\n\n**Run:**\n```bash\noh\noh --model llamacpp/my-model\noh models                    # list available models\n```\n\n## Auth\n\nProvider-agnostic credential management. Local LLMs (Ollama / llama.cpp / LM Studio) need no auth — configure them via `oh init`.\n\n```bash\noh auth login [provider] [--key \u003cvalue\u003e]   # store API key for a provider\noh auth logout [provider]                   # clear stored API key\noh auth status                              # show stored providers + env-var overrides\n```\n\n`[provider]` defaults to your configured default. `--key` supplies the value inline; otherwise OH prompts (TTY) or reads from stdin (piped).\n\n### Script-based key resolution (`apiKeyHelper`)\n\nAvoid storing keys in plaintext / the encrypted store by plugging in a helper script (1Password, `pass`, vault, cloud secret manager). The configured command runs at credential-fetch time with `OH_PROVIDER` set, and its trimmed stdout becomes the key.\n\n```yaml\n# .oh/config.yaml\napiKeyHelper: 'op read \"op://Personal/Anthropic/key\"'\n```\n\nResolution priority: env var → encrypted store → `apiKeyHelper` → legacy plaintext config.\n\n## Update\n\n```bash\noh update                    # detects how OH was installed (npm-global / npx / local clone) and prints the right upgrade command\n```\n\n## Configuration Hierarchy\n\nConfig is loaded in layers (later overrides earlier):\n\n1. **Global** `~/.oh/config.yaml` — default provider, model, theme for all projects\n2. **Project** `.oh/config.yaml` — project-specific settings\n3. **Local** `.oh/config.local.yaml` — personal overrides (gitignored)\n\nSet your default provider once globally:\n\n```yaml\n# ~/.oh/config.yaml\nprovider: ollama\nmodel: llama3\npermissionMode: ask\ntheme: dark\nlanguage: zh-CN        # optional — respond in this language (code stays as-is)\noutputStyle: default   # optional — \"default\", \"explanatory\", \"learning\", or a custom name\n```\n\nThen per-project configs only need what's different:\n\n```yaml\n# .oh/config.yaml\nmodel: codellama   # override just the model\n```\n\n### Output Styles\n\nSwap the agent's personality without touching its core instructions. Built-ins:\n\n- **`default`** — standard software engineering assistant (no preface)\n- **`explanatory`** — adds an `## Insights` section after each task explaining *why* the agent made its choices\n- **`learning`** — leaves 1–3 `TODO(human)` markers at strategic points so you write the instructive parts yourself\n\nCreate your own styles as markdown files with YAML frontmatter. Save to `.oh/output-styles/\u003cname\u003e.md` (project) or `~/.oh/output-styles/\u003cname\u003e.md` (user). Project shadows user shadows built-in.\n\n````markdown\n---\nname: code-review\ndescription: Focused code review mode\n---\n\nReview rigorously. For every function, ask: is the logic correct, is error handling complete, are there edge cases ignored?\n````\n\nActivate with `outputStyle: code-review` in `.oh/config.yaml`.\n\n## Project Rules\n\nCreate `.oh/RULES.md` in any repo (or run `oh init`):\n\n```markdown\n- Always run tests after changes\n- Use strict TypeScript\n- Never commit to main directly\n```\n\nRules load automatically into every session.\n\n## Skills \u0026 Plugins\n\n### Skills\n\nSkills are markdown files with YAML frontmatter that add reusable behaviors:\n\n```markdown\n---\nname: deploy\ndescription: Deploy the application to production\ntrigger: deploy\ntools: [Bash, Read]\n---\n\nRun the deploy script with health checks...\n```\n\n**Locations** (searched in order):\n1. `.oh/skills/` — project-level skills\n2. `~/.oh/skills/` — global skills (available in all projects)\n\nSkills auto-trigger when the user's message contains the trigger keyword, or can be invoked explicitly with `/skill deploy`.\n\n### Plugins\n\nPlugins are npm packages that bundle skills, hooks, and MCP servers:\n\n```json\n{\n  \"name\": \"my-openharness-plugin\",\n  \"version\": \"1.0.0\",\n  \"skills\": [\"skills/deploy.md\", \"skills/review.md\"],\n  \"hooks\": {\n    \"sessionStart\": \"scripts/setup.sh\"\n  },\n  \"mcpServers\": [\n    { \"name\": \"my-api\", \"command\": \"npx\", \"args\": [\"-y\", \"@my-org/mcp-server\"] }\n  ]\n}\n```\n\nSave as `openharness-plugin.json` in your npm package root. Install with `npm install`, and openHarness discovers it automatically from `node_modules/`.\n\n## How It Works\n\n```mermaid\ngraph LR\n    User[User Input] --\u003e REPL[REPL Loop]\n    REPL --\u003e Query[Query Engine]\n    Query --\u003e Provider[LLM Provider]\n    Provider --\u003e LLM[Ollama / OpenAI / Anthropic]\n    LLM --\u003e Tools[Tool Execution]\n    Tools --\u003e Permissions{Permission Check}\n    Permissions --\u003e|Approved| Execute[Run Tool]\n    Permissions --\u003e|Blocked| Deny[Deny \u0026 Report]\n    Execute --\u003e Response[Stream Response]\n    Response --\u003e REPL\n```\n\n## FAQ\n\n**Does it work offline?**\nYes. Use Ollama with a local model — no internet or API key needed.\n\n**How much does it cost?**\nFree. OpenHarness is MIT licensed. You bring your own API key (BYOK) for cloud models, or use Ollama for free.\n\n**Is it safe?**\nYes. 7 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 reversible with `/rewind`.\n\n**Can I use it in CI/CD?**\nYes. Use `oh -p \"prompt\" --auto` for headless execution, or the built-in GitHub Action for PR reviews.\n\n**Does it support my language/framework?**\nYes. OpenHarness is language-agnostic — it reads, writes, and executes code in any language. Syntax highlighting covers 20+ languages.\n\n**How does it compare to Claude Code?**\n~95% feature parity for CLI use cases. Main advantage: works with ANY LLM (not just Anthropic) and is MIT-licensed. See [Why OpenHarness?](#why-openharness) above.\n\n## Install\n\nRequires **Node.js 18+**.\n\n```bash\n# From npm\nnpm install -g @zhijiewang/openharness\n\n# From source\ngit clone https://github.com/zhijiewong/openharness.git\ncd openharness\nnpm install \u0026\u0026 npm install -g .\n```\n\n## Development\n\n```bash\nnpm install\nnpx tsx src/main.tsx              # run in dev mode\nnpx tsc --noEmit                  # type check\nnpm test                          # run tests\n```\n\n### Adding a tool\n\nCreate `src/tools/YourTool/index.ts` implementing the `Tool` interface with a Zod input schema, register it in `src/tools.ts`.\n\n### Adding a provider\n\nCreate `src/providers/yourprovider.ts` implementing the `Provider` interface, add a case in `src/providers/index.ts`.\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## Community\n\nJoin the OpenHarness community to get help, share your workflows, and discuss the future of AI coding agents!\n\n| Platform | Details \u0026 Links |\n| :--- | :--- |\n| 🟣 **Discord** | [**Join our Discord Server**](https://discord.gg/ezVrqy3qu) to chat with developers and get real-time support. |\n| 🔵 **Feishu / Lark** | Scan the QR code below to collaborate with the community:\u003cbr\u003e\u003cbr\u003e\u003cimg src=\"https://github.com/user-attachments/assets/54ade077-22ad-45d2-b38a-623464677d53\" width=\"160\" alt=\"Feishu Group QR Code\"\u003e |\n| 🟢 **WeChat** | Scan the QR code below to join our WeChat group:\u003cbr\u003e\u003cbr\u003e\u003cimg src=\"https://github.com/user-attachments/assets/adcf291a-9ffe-4738-8608-f46a21e18db0\" width=\"160\" alt=\"WeChat Group QR Code\"\u003e |\n\n## License\n\nMIT\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzhijiewong%2Fopenharness","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzhijiewong%2Fopenharness","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzhijiewong%2Fopenharness/lists"}