# Examples

Find the right runnable workflow.

For a small, standalone starting point, try the [research agent](../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:

~~~bash
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:

~~~bash
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](../web-demo/) 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.

~~~bash
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](../streaming/#show-that-a-slow-call-is-still-working) |
| `04-context/planning_todos.py` | `write_todos` and `read_todos` on a multi-step task, and the `TODOS_UPDATED` events | [Long-run reliability](../loop-reliability/#a-plan-the-model-keeps-seeing) |
| `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](../loop-reliability/#condensing-a-history-that-has-outgrown-its-window) |
| `05-control/loop_guard.py` | `LoopGuard` catching the same call repeating, the `REPETITION` hook, and the note the model reads | [Long-run reliability](../loop-reliability/#noticing-a-loop) |
| `05-control/retries_and_fallback.py` | `RetryPolicy` retrying a 503, then `FallbackProvider` switching to a backup | [Retries & fallback](../retries-and-fallbacks/) |
| `06-durability/session_snapshots.py` | `save_session` and `Agent.load_session` into a fresh agent, the step before a durable runtime | [Sessions](../sessions/#save-a-conversation-snapshot) |

## 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](../providers/#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/) | `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](../decisions/). 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](../backends/#crash-and-resume). The browser launch runs the live streaming example; the recovery walkthrough uses separate terminal commands.

## Launch from a browser

[harness-web](../web-demo/) 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`.
