基于 PydanticAI 的策略门控 CLI 编码智能体 the-harness 发布
mehdinourollah/the-harness
mehdinourollah/the-harness 是一个基于 PydanticAI 的策略门控 CLI 编码智能体,支持 OpenAI、Anthropic、vLLM、Ollama、DeepSeek 等兼容端点,内置 14 个 workspace 工具,涵盖文件读写、grep、shell 命令、完整 git 流程与网页搜索。
A small, policy-gated CLI coding agent built on PydanticAI.
Talk to your codebase. The agent reads, edits, greps, runs commands, and uses git — behind an explicit policy object, with live tool-call rendering and optional Langfuse tracing.
Features
- Any OpenAI- or Anthropic-compatible endpoint — OpenAI, vLLM, LiteLLM,
Ollama, Groq, DeepSeek, or a local proxy. Point
--base-urlat it and go. - 14 workspace tools — read/write/patch files, list/grep/glob the tree, run shell commands, full git flow (status/diff/commit/log/checkout), web search and page fetch.
- Policies, not flags —
readonly,auto-approve,interactive. Reads always pass; writes, commands, and network obey the policy. A refused action is fed back to the model as a retry prompt, so it self-corrects instead of crashing. - Conversation memory — the REPL carries message history and cumulative
token/cost usage across turns (
2 req · 3 tool · 1.2k tok · $0.004after every answer).--no-historystarts each turn fresh. - Live Claude-Code-style rendering — every tool call and its output streams to the terminal as it happens; errors arrive as red panels, answers close with a token/cost footer.
- Real inputs, styled output — prompt_toolkit editing with persistent
command history (
~/.the-harness/history) when interactive; plaininput()when piped, so scripts and CI behave exactly as before. - Langfuse observability —
--traceexports model and tool spans over OTLP to a self-hosted Langfuse stack (docker-compose.langfuse.ymlincluded).
PydanticAI owns the agent loop, streaming, retries, provider adapters, tool schemas, and history. This repo owns the tools, the policy layer, the CLI, and the tracing wiring. See ARCHITECTURE.md for the blueprint.
Getting Started
Install with one command:
curl -LsSf https://raw.githubusercontent.com/mehdinourollah/the-harness/main/install.sh | shThat drops the harness command into ~/.local/bin. Or install from source:
git clone https://github.com/mehdinourollah/the-harness cd the-harness python3.11 -m venv .venv && source .venv/bin/activate pip install -e ".[dev]"
Run it:
export ANTHROPIC_API_KEY=... # or --api-key, or OPENAI_API_KEY harness --provider anthropic --model claude-sonnet-5-5 "find the auth bug" harness # REPL
Against a local proxy:
harness --provider openai --base-url http://localhost:8080/v1 \
--model my-model --policy auto-approve "write a test for the cache"Traced, to your local Langfuse:
export LANGFUSE_PUBLIC_KEY=... LANGFUSE_SECRET_KEY=... harness --trace --policy readonly "audit this repo for publish risks"
harness --provider PROVIDER --model MODEL --policy POLICY [prompt ...]
--provider openai | anthropic (default: openai)
--base-url any compatible endpoint (default: vendor default)
--api-key or set OPENAI_API_KEY / ANTHROPIC_API_KEY
--policy readonly | auto-approve | interactive
--no-history REPL: each turn starts fresh
--trace export spans to Langfuse
--langfuse-host (default: http://localhost:3000)
--workspace confine tools to this tree (default: .)
--max-turns per-run step budget (default: 24)
Tools
| Area | Tools |
|---|---|
| Files | view_file · write_file · patch_file · list_directory · grep_search · glob_search |
| Shell | execute_command |
| Git | git_status · git_diff · git_commit · git_log · git_checkout_branch |
| Web | web_search · browse_url |
Every side-effecting tool declares the Actions it performs (read, write,
execute, network); the policy decides. Adding a tool is one async function
plus one ts.add_function(...) line in
harness/tools/__init__.py — signatures and
docstrings become the tool schema.
Local Langfuse
A ready-to-boot self-hosted stack, no account needed:
cp .env.example .env.langfuse # fill in if desired; defaults boot fine
docker compose -f docker-compose.langfuse.yml --env-file .env.langfuse up -dOpen http://localhost:3000, then pass --trace. Ingestion can be verified
without the UI via GET /api/public/v2/observations (the legacy /traces
endpoint is disabled in Langfuse v4 events-only mode).
Development
pytest # 118 tests pytest --cov=harness --cov-report=term-missing --cov-fail-under=100 ruff check . && ruff format --check . # lint pyright harness # types (0 errors enforced in CI)
Quality gates, in order of speed: pre-commit hooks (ruff, codespell, whitespace)
run on commit; the full pytest suite with a 100% coverage gate runs on
push; GitHub Actions runs lint, pyright, and the test matrix (3.11/3.12/3.13)
behind a single all checks passed gate. Install the hooks with
.venv/bin/pre-commit install.
Contributing
Bug reports and small, focused PRs are welcome. Keep the diff tight: PydanticAI already handles the loop, providers, and retries, so new code belongs in tools, policy, CLI, or tracing — and every new branch needs a test (the coverage gate is 100%). Run the hooks before you push.
License
MIT — do what you want, keep the notice.
来源:GitHub · github.com