A minimal Agent Harness core — ReAct loop + tool registry + permission model
Project description
Mini Harness
A minimal Agent Harness core — the smallest complete implementation of an agent runtime. 1001 lines of Python. 49 tests. DeepSeek-first.
ReAct agent loop, streaming tool-call delta concatenation, 7-tool registry, 3-tier permission model, checkpoint/resume, step-level observability.
Demo
See demos/ — screenshots and HTML terminal replay covering all 5 features.
What is this?
The "brain + body" of an AI agent — the runtime shell that turns a raw LLM into a tool-using, permission-gated, controllable agent.
Does:
- ReAct agent loop with streaming (think → act → observe → repeat)
- 7 tools: read, write, edit, grep, glob, bash, fetch
- Tool call delta concatenation (streamed arguments assembled by index)
- 3-tier permission model (read / yn / auto) + hard-wall
- Step trace: timing, token count, step counter per turn
- Interrupt/Resume: Ctrl+C mid-run → rollback to checkpoint → continue/discard
- Write verification: auto-read after write to prevent fake success
Does NOT:
- Knowledge management, multi-agent, web dashboards, skill systems
Architecture
User Input
│
▼
┌──────────────────────────────────────┐
│ Agent (loop.py) │
│ │
│ save_checkpoint() │
│ async for delta in chat_stream(): │
│ yield text_delta ← streaming │
│ accumulate tool_call deltas │
│ assemble response │
│ for each tool_call: │
│ permission gate ──────────────┐ │
│ execute handler (async) │ │
│ result → messages ────────────┘ │
│ yield summary (steps/duration/tok) │
└──────────────────────────────────────┘
│ │ │
▼ ▼ ▼
┌─────────┐ ┌──────────┐ ┌──────────────┐
│ llm.py │ │ tools.py │ │permissions.py│
│DeepSeek │ │ 7 tools │ │ read/yn/auto │
│streaming│ │ unified │ │ + hard-wall │
│+ tokens │ │ async │ │ │
└─────────┘ └──────────┘ └──────────────┘
Install
pip install mini-harness
# or dev:
pip install -e .
Quick Start
CLI
mini-harness
First run prompts for your DeepSeek API key (saved to ~/.mini-harness/config.toml).
> 列出当前目录的 Python 文件
[1/15] glob · 0.8s · 45t
[2/15] text · 0.3s · 89t
— 2 steps · 1.1s · 134t
main.py
cli.py
Ctrl+C mid-run → [C]ontinue [D]iscard [Q]uit.
API
import asyncio
from harness import Agent, DeepSeekClient, Mode
async def main():
client = DeepSeekClient(api_key="sk-...")
agent = Agent(client, system_prompt="You are a helpful assistant.",
mode=Mode.AUTO)
async for event in agent.run("List Python files in this project"):
if event["type"] == "text_delta":
print(event["text"], end="", flush=True)
elif event["type"] == "tool_call":
print(f"\n [{event['step']}/{event['max_steps']}] {event['tool']}")
elif event["type"] == "summary":
print(f"\n — {event['steps']} steps · "
f"{event['duration_ms']/1000:.1f}s · {event['tokens']}t")
asyncio.run(main())
Event Reference
| Event | Fields | When |
|---|---|---|
text_delta |
text |
Per-chunk during streaming |
tool_call |
tool, params, step, max_steps, duration_ms, tokens |
Before tool execution |
tool_result |
tool, success, output, step |
After tool execution |
step_end |
step, kind, duration_ms, tokens |
Text-only responses |
summary |
steps, duration_ms, tokens |
End of turn |
interrupted |
step, message |
Ctrl+C caught |
error |
message |
API failure, max steps |
Permission Modes
| Mode | Read | Write | Bash | Hard-wall bypass? |
|---|---|---|---|---|
| Read | ✅ | ❌ | ❌ | No |
| YN | ✅ | Prompt | Prompt | No |
| Auto | ✅ | ✅ | ✅ | No |
Hard-wall (permanently blocked): rm -rf, sudo, git push --force,
paths: raw/, agents/, archive/, /etc/, /proc/, /sys/.
Project Structure
mini-harness/
├── harness/
│ ├── __init__.py # Public API
│ ├── cli.py # REPL with interrupt dialog
│ ├── loop.py # Agent Loop + streaming + checkpoint
│ ├── llm.py # DeepSeek API (streaming + usage)
│ ├── tools.py # 7 tools + registry + async handlers
│ └── permissions.py # 3-tier + hard-wall
├── tests/ # 49 tests
├── README.md
├── CHANGELOG.md
└── pyproject.toml
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mini_harness-1.0.1.tar.gz.
File metadata
- Download URL: mini_harness-1.0.1.tar.gz
- Upload date:
- Size: 19.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3a1ff0a9d6574a74bb0eca2e19063d7755065a4ed1f8df691012c19cefdcae61
|
|
| MD5 |
e694ab51322298c673dfa8feca337f84
|
|
| BLAKE2b-256 |
ee1482710a211e8185d54b7c4a0a3e40788c79db8701fd078485b517fa0c6549
|
File details
Details for the file mini_harness-1.0.1-py3-none-any.whl.
File metadata
- Download URL: mini_harness-1.0.1-py3-none-any.whl
- Upload date:
- Size: 14.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a08a64c884631905785a78b5ef0079440bc646804ea15e8e461dc74efd20b599
|
|
| MD5 |
c4d1465b9d8aaeb22f8e3a4bf04e53f7
|
|
| BLAKE2b-256 |
e9b664ad6863e74224cf806ba320c61932df502a1a785035e915897c716a1fcb
|