Skip to content

Building An Inspectable Agent Harness

This tutorial reconstructs the project from the beginning to the current runtime. It is based on the git history, the current codebase, and the design decisions that have been encoded in it.

It is not a source-code reference. It is a guided explanation of why the code is split the way it is.

Chinese mirror: ../zh/README.md

Chapter Map

ChapterTopicWhy It Exists
00Environment setup and first runFor readers crossing over: install the toolchain, get an API key, and complete a first Chat call and Agent run in the UI and with curl.
01Project starting point and constraintsEstablish the learning repo, explicit style, and smallest runnable API path.
02API contracts and validationKeep HTTP, DTO, config, and service boundaries readable before agent complexity.
03Living architecture and workbenchMake the project explain itself as it grows.
04First agent and observabilityAdd /api/agent, steps, structured logs, and the first inspectable tool flow.
05Streaming, cancellation, and eventsTurn the agent into a live run with abort and internal runtime events.
06Tool runtime and permission skeletonMove execution behind a runtime boundary before adding risky tools.
07JSONL sessions and usagePersist runs and separate raw provider usage from normalized totals.
08Provider dialect boundaryKeep OpenAI Chat/Responses quirks out of the agent loop.
09Response items and runtime spineReplace fixed teaching steps with provider-neutral model-visible history.
10Streaming sampling and commit semanticsExplain deltas, committed assistant messages, tool calls, and final answer detection.
11Deterministic runtime testsProve the loop without calling a real provider.
12Real read-only toolsReplace toy capability with ls, find, grep, and read.
13Tool output and strict OpenAI schemaSeparate internal metadata from model-visible text and handle OpenAI strict schemas.
14Debug Console and session viewerSplit end-user transcript, runtime debug, and persisted JSONL views.
15Tool contract boundary and toy removalAdd source/group/path/execution metadata and remove the toy tool.
16Unlimited loop and guardrailsRemove the artificial round cap while stopping repeated identical tool loops.
17Current state and next stepsSummarize what is real now and what must come next.
18Shell tool and command safetyGive the model a shell behind a safe-command classifier and tool-level permission override.
19Approval pause and resumeTurn an ask decision from an immediate failure into a suspend-and-wait that resumes after approval or denial.
20Session replay and resumeTurn a single-turn JSONL session into a real multi-turn conversation that can be continued.
21Context compactionCompact history automatically once a token threshold is reached, so long conversations don't grow without bound.
22Frontend dark mode and polishAdd system-level dark mode and verify the Agent/Chat workbench page by page.
23The gap map to production harnessesDraw the book's boundary proactively: against Codex/Claude Code, list the missing mechanisms, why they were skipped, and when they become worth building.
24OS-level sandboxGraduate the chapter 18 lexical classifier to kernel enforcement: macOS sandbox-exec + Linux bwrap, fail-closed, carveouts protect .git / .env / sessions.
25Tracing and subagentsTurn the event stream into a span tree, derive subagents through a task tool with their own context and session file, and export to any OTLP backend without taking a vendor dependency.

Beyond the chapter table there is an appendix of prerequisite bridges for readers crossing over from another stack: TypeScript unions, Zod, the App Router, SSE, the tool-calling protocol, and async ordering.

How To Read

If you are crossing over from another stack (say, a Java/Python background), read chapter 00 first to get the environment and API key working; while reading the main text, consult the prerequisites appendix whenever you hit a concept gap — no need to study it up front.

If you are new to the project, read chapters 01 through 05 first. They explain why this repo values explicit boundaries and inspectability.

If you want the current agent runtime, read chapters 08 through 16 plus 18 through 21. They cover the provider-neutral loop, real tools, debug surface, session records, loop guardrails, the shell boundary, approval pause/resume, session resume, and context compaction. Chapter 22 is frontend polish, independent of the runtime evolution thread, and can be read on its own.

If you are adding the next capability, read chapter 17 before implementing it. The next layer should follow the same discipline: define the boundary, expose the data flow, write real tests, and update the tutorial.

Main Thread

The central idea is:

text
The model supplies reasoning.
The harness supplies the runtime where that reasoning can safely act.

In this project, the harness owns:

  • route boundaries
  • input validation
  • provider dialects
  • streaming events
  • model-visible history
  • tools
  • permissions
  • cancellation
  • debug surfaces
  • session records
  • loop guardrails

That is why the tutorial spends more time on boundaries than on prompts.