CHAPTER 17 · Building the Full Mini-Harness · 4 / 10
Step 2: wire the loop
agent.py brings every component together. Read it top to bottom; the comments name the chapter each piece comes from.
# minharness/agent.py
"""The integration layer: one agent loop wiring every chapter together."""
from .model import call_model
from .prompt import PromptBuilder, user_msg, tool_call, tool_result
from .context import Compactor, estimate_items_tokens
from .tools import ToolRegistry, Tool, shell_handler
from .approvals import ApprovalPolicy, gated_call
from .parallel import run_tools
from .memory import MemoryLoader
from .skills import SkillLoader
from .control import HookManager, Budget, BudgetExceeded
from .subagents import spawn_subagent, VERIFIER
class MiniHarness:
def __init__(self, project_root: str, mode: str = "default"):
# --- Chapter 6: the tool registry (the agent's hands) ---
self.registry = ToolRegistry()
self.registry.register(Tool(
name="shell", description="Run a shell command",
parameters={"type": "object",
"properties": {"command": {"type": "string"}},
"required": ["command"]},
handler=shell_handler))
# --- Chapter 7: the safety gate in front of every tool ---
self.policy = ApprovalPolicy(allowlist=[r"^ls", r"^cat", r"^pytest"], mode=mode)
# --- Chapter 9 + 10: project memory and skills feed the prompt ---
self.memory = MemoryLoader(project_root)
self.skills = SkillLoader(f"{project_root}/.skills")
# --- Chapter 3 + 9 + 10: the prompt assembler ---
self.prompt = PromptBuilder(
base_instructions="You are minharness, a careful coding agent.",
project_instructions=self.memory.load_instructions(project_root),
skills_summary=self.skills.summary(),
cwd=project_root,
tools=self.registry.schemas())
# --- Chapter 4 + 5: context management ---
self.compactor = Compactor(max_tokens=8000, keep_recent=6)
# --- Chapter 12: deterministic control + budget kill switch ---
self.hooks = HookManager()
self.hooks.register("PreToolUse", _block_dangerous)
self.budget = Budget(max_turns=25, max_cost=5.0)
def _execute_call(self, call: dict) -> str:
"""One tool call: hooks -> approval -> registry (Ch 12, 7, 6)."""
veto = self.hooks.fire("PreToolUse", call)
if veto.get("block"):
return f"Exit code: 126\nBlocked by hook: {veto['reason']}"
return gated_call(self.registry, self.policy, call["name"], call["args"],
unattended=(self.policy.mode == "full-auto"))
def run(self, user_request: str) -> str:
history = [user_msg(user_request)] # Chapter 3
while True:
history = self.compactor.compact(history) # Chapter 5
request = self.prompt.build_request(history) # Chapter 3
try:
self.budget.charge(str(request), "") # Chapter 12
except BudgetExceeded as e:
return f"Stopped: {e}"
response = call_model(request) # Chapter 2
if response["type"] == "text": # turn ends
return response["content"]
# one or more tool calls: run them (parallel-safe) -> append results
calls = response["calls"] # Chapter 8
for c in calls:
history.append(tool_call(c["call_id"], c["name"], c["args"]))
results = run_tools(calls, lambda c: self._execute_call(c))
for r in results:
history.append(tool_result(r["call_id"], r["output"]))
def review(self, claim: str): # Chapters 11, 13
"""Optional: delegate an independent check to a verifier subagent."""
return spawn_subagent(VERIFIER, f"Verify: {claim}",
lambda h, m: "VERIFIED (stub)", self.registry)
def _block_dangerous(payload): # Chapter 12 hook
cmd = payload.get("args", {}).get("command", "")
if any(x in cmd for x in ("rm -rf", "git push", "curl")):
return {"block": True, "reason": f"dangerous command: {cmd!r}"}