For a small, standalone starting point, try the research agent: search the web through MCP, compare options, and save a Markdown report with source links. Its complete Python script is available to copy or download from that guide.
The examples below live in the repository, not in the PyPI package. Each one is a single Python file that you run by its path. Clone the repository once and let uv build the environment:
git clone https://github.com/datagol/agent-harness-x.git
cd agent-harness-x
uv sync --all-extras
uv run python examples/05-control/loop_guard.py
The examples are plain scripts, not a package. Run them by path, not as a module with python -m. Each file imports only harnessx, the standard library, python-dotenv, and the optional SDK it is about. Each loads the repository's .env without replacing variables already set in your shell. So you can copy any file into your own project after pip install harnessx, and it runs the same.
The folders go in reading order, from a first chat to isolation: 01-basics, 02-tools, 03-skills, 04-context, 05-control, 06-durability, 07-quality, and 08-sandboxes.
Run the examples with Docker Compose
The repository's docker-compose.yml runs the examples in containers, with PostgreSQL, Temporal and Redis already provisioned and no Python or Node to install. From the repository root:
docker compose up --build
docker compose run --rm web python examples/03-skills/skills_lazy_loading.py
The first command builds the image and starts harness-web at http://localhost:8765. The second runs one example in the same image. The web container gets DATABASE_URL, TEMPORAL_TARGET and REDIS_URL pointing at the bundled services, so 06-durability/durable_crash_recovery.py needs no database of your own. Model keys come from the repository's .env, read at run time and never baked into the image. Ports are published on loopback only.
No API key needed
These use a scripted model against the real engine, tools, hooks, approvals, recorder, or evaluations. They show how the pieces fit together, not how good a model is.
uv run python examples/01-basics/prompt_caching.py
uv run python examples/01-basics/progress_and_waiting.py
uv run python examples/03-skills/skills_lazy_loading.py
uv run python examples/04-context/planning_todos.py
uv run python examples/04-context/condensing_a_long_history.py
uv run python examples/05-control/loop_guard.py
uv run python examples/05-control/retries_and_fallback.py
uv run python examples/06-durability/tool_approvals_and_resume.py # asks one question
uv run python examples/06-durability/session_snapshots.py
uv run python examples/07-quality/decisions_routing.py --min-confidence 0.8
uv run python examples/07-quality/decisions_answer_review.py
uv run python examples/07-quality/flight_recorder.py --output /tmp/invoice-incident.hx
uv run python examples/07-quality/evaluating_with_datasets.py --offline # needs the langsmith extra
Single-feature recipes
Six examples each show a single feature with a scripted model, so none of them needs an API key.
| File | What it shows | Read more |
|---|---|---|
01-basics/progress_and_waiting.py |
A long run's event stream, including the WAITING events sent while a slow model call is quiet |
Streaming |
04-context/planning_todos.py |
write_todos and read_todos on a multi-step task, and the TODOS_UPDATED events |
Long-run reliability |
04-context/condensing_a_long_history.py |
Old tool output cleared first, then a summary, when the history outgrows max_context_tokens |
Long-run reliability |
05-control/loop_guard.py |
LoopGuard catching the same call repeating, the REPETITION hook, and the note the model reads |
Long-run reliability |
05-control/retries_and_fallback.py |
RetryPolicy retrying a 503, then FallbackProvider switching to a backup |
Retries & fallback |
06-durability/session_snapshots.py |
save_session and Agent.load_session into a fresh agent, the step before a durable runtime |
Sessions |
Every example
Paths are relative to examples/. Prefix each with uv run python examples/.
01-basics
| File | What it shows | Needs |
|---|---|---|
prompt_caching.py |
Prefix keys, cache hints, and cache write and read counters for a stable prompt prefix. --off disables caching |
Nothing; --live uses an Anthropic key |
progress_and_waiting.py |
A long run's event stream, including the WAITING events from ProgressPolicy |
Nothing |
media_input.py [PATH] |
An image, PDF or audio clip sent with the text of a turn as content blocks, on Gemini. With no path it sends a 1x1 PNG held in the script. HARNESSX_MODEL selects the model. See Images, documents and audio |
gemini extra and GEMINI_API_KEY |
streaming_chat.py |
Interactive streaming chat with a bounded calculator and read-only workspace tools. usage prints token counts |
Anthropic key |
switching_providers.py --provider P --model M |
The same agent on Anthropic, OpenAI, Gemini, OpenRouter, or Azure OpenAI. --no-stream gives ordinary results, --prompt runs one prompt and exits. On Azure --model is the deployment name |
The provider's extra and key |
02-tools
| File | What it shows | Needs |
|---|---|---|
filesystem_tools_and_permissions.py |
The file and shell built-ins under CliPermissionManager: reads allowed, writes and commands asked first |
Anthropic key |
mcp_servers.py --server NAME --command CMD |
Tools from an MCP server next to native tools, over stdio or SSE, with approvals for MCP tools | mcp extra, an MCP server, Anthropic key |
03-skills
| File | What it shows | Needs |
|---|---|---|
skills_lazy_loading.py |
The model sees a skill catalog and loads one body with the Skill tool, with hook ordering |
Nothing |
skills_interactive.py |
A live model picking skills from examples/skills/ when the task calls for them. AGENT_PROVIDER and AGENT_MODEL select the model |
Anthropic key by default |
04-context
| File | What it shows | Needs |
|---|---|---|
planning_todos.py |
write_todos and read_todos on a multi-step task, and the TODOS_UPDATED events |
Nothing |
condensing_a_long_history.py |
Old tool output cleared first, then a summary, when the history outgrows max_context_tokens |
Nothing |
knowledge_bundles_okf.py |
Search, concept reads, and link traversal over the Open Knowledge Format bundle in examples/knowledge/. AGENT_KNOWLEDGE points at another folder or git URL |
Anthropic key by default |
custom_memory_tools.py |
The built-in save_memory and recall_memories, plus two tools of your own over the same stores under .agent_memory/ |
Anthropic key |
05-control
| File | What it shows | Needs |
|---|---|---|
loop_guard.py |
LoopGuard catching the same call repeating, the REPETITION hook, and the note the model reads |
Nothing |
retries_and_fallback.py |
RetryPolicy retrying a 503, then FallbackProvider switching to a backup |
Nothing |
delegating_to_subagents.py "TASK" |
An orchestrator handing one task to specialists declared with Agent(subagents=[...]). With no task it runs a built-in one |
Anthropic key |
autonomous_task_runner.py "TASK" |
One task from the command line: the agent writes the deliverable and runs it | Anthropic key; TAVILY_API_KEY adds web search, LANGSMITH_API_KEY tracing |
06-durability
| File | What it shows | Needs |
|---|---|---|
tool_approvals_and_resume.py |
A run paused on an ASK tool, persisted on SQLite, then finished with approve(pending, resume=True) |
Nothing; answers one question |
session_snapshots.py |
save_session and Agent.load_session into a fresh agent |
Nothing |
durable_crash_recovery.py |
Live streaming on the PostgreSQL runtime | postgres extra, DATABASE_URL or --config PATH, Anthropic key |
durable_crash_recovery.py check / crash / status / resume |
Storage check, a written report, a hard process exit, and recovery without repeating the tool | postgres extra and a database; no model key |
07-quality
| File | What it shows | Needs |
|---|---|---|
decisions_routing.py --min-confidence 0.8 |
A Choice decision classifies a document as W2, Deposit, Insurance, Payroll, or unknown, then selects one of three agents. Unknown, uncertain, or unavailable decisions fall back to a general agent | Nothing by default; --live needs the jev extra and --model |
decisions_answer_review.py |
After a completed run, Score reviews coverage and Noul assesses evidence support | Nothing by default; --live needs the jev extra |
flight_recorder.py --output incident.hx |
A failed and retried model call, middleware boundaries, an exported incident bundle, and playback with no model or tool calls | Nothing; the output path must not exist |
evaluating_with_datasets.py --offline |
A small dataset of tool-selection and arithmetic cases, scored through the evaluation library. Drop --offline for a live model and uploads |
langsmith extra |
tracing_with_langsmith.py |
One LangSmith run tree per turn, with spans for model and tool calls | langsmith extra, Anthropic and LangSmith keys |
08-sandboxes
| File | What it shows | Needs |
|---|---|---|
sandbox_isolation_tiers.py --tier T |
A coding agent running its Python in a Sandbox. process is the default and is not an isolation boundary; docker and seatbelt isolate the code |
Anthropic key; Docker for --tier docker |
openshell_backend.py |
The agent's shell and file tools run in an NVIDIA OpenShell sandbox; the project is copied in and changes come back after each run. See OpenShell sandbox | openshell extra, a running OpenShell gateway, Anthropic key |
examples/skills/ holds sample skills and examples/knowledge/ a sample Open Knowledge Format bundle.
The decision examples use fixed decision fixtures, so changing their input does not change the offline decision. Add --live and TYPESAFE_API_KEY for real decisions; see Decisions with Jev. Routing needs an explicit confidence threshold. 0.8 demonstrates the setting and is not a calibrated default.
For the PostgreSQL crash scenario, copy examples/06-durability/postgres.config.example.json to postgres.config.json in the same folder and follow the durability walkthrough. The browser launch runs the live streaming example; the recovery walkthrough uses separate terminal commands.
Launch from a browser
harness-web runs every example. Its library lists each script in examples/, grouped by the same topics as the folders, and runs the file unchanged as python examples/<topic>/<file>.py. It shows input, approvals, stream output with tool calls as they happen, and downloads. Its other half, Build your agent, lets you write the prompt, upload skills, connect MCP servers, and add subagents. Start it with docker compose up --build.