# harness

> Thin durable turn loop that wires session-manager, context-manager, and llm-router into an agent loop; spawns sub-agents as child sessions.

| field | value |
|-------|-------|
| version | 1.8.15 |
| type | binary |
| license | Apache-2.0 |
| repo | https://github.com/iii-hq/workers |
| supported_targets | aarch64-apple-darwin, x86_64-pc-windows-msvc, aarch64-pc-windows-msvc, x86_64-unknown-linux-gnu, aarch64-unknown-linux-gnu, x86_64-unknown-linux-musl, armv7-unknown-linux-gnueabihf |
| author | iii |

## installation

```sh
iii trigger compose::add worker=harness@1.8.15
```

## dependencies

- `configuration` @ `0.x`
- `console` @ `^1.9.11`
- `context-manager` @ `^1.1.3`
- `cron` @ `^0.21.9`
- `iii-directory` @ `^1.2.3`
- `iii-observability` @ `0.x`
- `iii-stream` @ `0.x`
- `llm-router` @ `^1.4.12`
- `provider-anthropic` @ `^1.2.8`
- `provider-openai` @ `^1.2.7`
- `provider-openai-codex` @ `^0.4.4`
- `queue` @ `^0.21.5`
- `session-manager` @ `^1.0.13`
- `shell` @ `^0.11.9`
- `state` @ `^0.22.2`

## readme

<div align="center">

# harness

**A thin, durable turn loop that turns a model plus a few iii workers into an agent.**

<p>
  <a href="#install"><img alt="Install: iii trigger compose::add worker=harness" src="https://img.shields.io/badge/install-iii%20trigger%20compose%3A%3Aadd%20worker%3Dharness-0a84ff?style=flat-square"></a>
  <a href="../LICENSE"><img alt="License: Apache 2.0" src="https://img.shields.io/badge/license-Apache%202.0-blue.svg?style=flat-square"></a>
  <a href="https://www.rust-lang.org"><img alt="Built with Rust" src="https://img.shields.io/badge/built%20with-rust-orange?style=flat-square&logo=rust&logoColor=white"></a>
  <a href="https://workers.iii.dev/workers/harness"><img alt="harness on the workers registry" src="https://workers.iii.dev/workers/harness/badge.svg"></a>
  <a href="https://workers.iii.dev/workers/console"><img alt="console on the workers registry" src="https://workers.iii.dev/workers/console/badge.svg"></a>
</p>

</div>

`harness` is the thin, durable turn loop that turns a model plus a few iii
workers into an agent. It takes an incoming message, persists it, assembles a
context, streams a completion, runs any function calls the model requests, and
repeats until the turn stops — all as durable, resumable steps so a crash or
restart picks up mid-turn. It wires [`session-manager`](https://github.com/iii-hq/workers/tree/main/session-manager)
(transcript), [`context-manager`](https://github.com/iii-hq/workers/tree/main/context-manager) (token budgeting, soft
dependency), and [`llm-router`](https://github.com/iii-hq/workers/tree/main/llm-router) (generation); install those
alongside it for the full loop.

## Quickstart

Install the engine, export the Anthropic credential in the terminal that will
run the engine, initialize a project, and start it:

```bash
curl -fsSL https://install.iii.dev/iii/main/install.sh | sh
export ANTHROPIC_API_KEY='<your-anthropic-api-key>'
export OPENAI_API_KEY='<your-openai-api-key>'
iii project init iii-app && cd iii-app
iii compose --up
```

```bash
# New terminal, same folder. `compose::add` updates this Compose project.
cd iii-app
iii trigger compose::add worker=harness worker=console
```

```bash
open http://localhost:3113
```

Create a session, select **Anthropic → Claude Sonnet 5**, and send your first
message. Then select **OpenAI → GPT-5.6 Luna** in the same chat and send another
message. Create a new chat and send one more message with GPT-5.6 Luna. The
providers read `ANTHROPIC_API_KEY` and `OPENAI_API_KEY` from the engine
environment, so credentials do not need to be pasted into or stored by the
Console.

`iii trigger compose::add worker=harness` installs every worker the loop needs (see the badges
above); you do not add them one by one. During bootstrap, the harness asks the
`queue` worker to define a dedicated `harness-turn` queue before it reports
ready. That queue is FIFO within each `session_id` and processes separate
sessions concurrently; startup fails if the queue cannot be ensured.

Every turn, sub-agent spawn, and provider call is one correlated trace: the
harness turn waterfall in the console. Failed descendants stamp the whole trace
as failed and carry standard error attributes. The session transcript keeps the
same recovery, partial-output, and blocked-reaction explanation after refresh.

<p align="center">
  <img src="https://raw.githubusercontent.com/iii-hq/workers/main/harness/docs/images/console-traces.webp" alt="Harness turn waterfall in the iii console" width="100%">
</p>

The agent-facing function surface is deny-by-default: with no `functions.allow`
globs, every model-requested call is refused and the harness is a plain chat
loop. Allow functions in per-send (`options.functions.allow`) and gate them
with the optional [`approval-gate`](https://github.com/iii-hq/workers/tree/main/approval-gate) sibling.

The full function reference (every `harness::*` id and its request/response
schema) lives in the code and `iii worker info harness`.

Building a consumer — a chat UI, a Telegram/WhatsApp bridge, a cron worker, or
any event-driven loop on top of the harness? Start with the integration
contract in
[`architecture/integration.md`](architecture/integration.md): the functions to
trigger, the triggers to bind, and the canonical consumer patterns.

## Local development

See [`DEVELOPMENT.md`](DEVELOPMENT.md) to run the Harness and its required
workers from the local source tree with `iii compose`.

## Working with iii

iii is a language agnostic runtime where services, agents, and tools are
composed of the same things: workers, triggers, and functions. One engine
holds a live registry of every connected worker, their functions, and the
triggers bound to them. Calls route worker to engine to worker, so the
language, runtime, and location of a worker are invisible; the function id is
the only contract.

**1. Discover what is already there (the engine is the source of truth)**
- `engine::functions::list` — every function across all workers (filter with `prefix` / `search` / `worker`)
- `engine::functions::info { function_id }` — the request/response schema for ONE function (this is your API reference)
- `engine::workers::list` / `engine::workers::info { name }` — connected workers and their surface
- `engine::triggers::list` / `engine::triggers::info { id }` — legal trigger types and their config schemas
- `engine::registered-triggers::list` — every trigger instance already bound

**2. Call a function.** Use `agent_trigger` with `{ function: "<worker>::<fn>", description: "<short user-facing action>", payload: { ... } }`. The description is shown as the agent's activity in chat; keep it concise and in the user's language. The payload is a JSON object (never a stringified one), and you fetch the contract via `engine::functions::info` before the first call.

**3. Need a capability that is not registered?**
- `directory::registry::workers::list { search: "<capability>" }`
- `directory::registry::workers::info { name }` to judge fit
- choose an operation id and register a one-shot `compose-operation` wake with
  `{ "operation_id": "<operation-id>", "terminal_only": true }`
- call `compose::add { worker: "<name>", operation_id: "<operation-id>" }` with the same id
- read `compose::operation` once for race recovery, then confirm the functions after the terminal event

**4. Worker lifecycle.** `compose::status`, `compose::add`, `compose::up`, `compose::down`, `compose::restart`, `compose::update`, and `compose::remove`. `add`, `update`, and `remove` use the same `compose-operation` wake flow above; the other operations return their final result directly. `add`, `update`, and `remove` accept a `workers` list for one batch, while their singular `worker` field remains compatible. Fetch their contracts with `compose::schema { function_id: "compose::<operation>" }`. The harness routes `compose::*` to its supervising daemon and scopes each call to its own compose file.

**5. Triggers, not polling.** To react to events (HTTP, schedule, webhook, file change), bind a trigger instead of polling. Discover the type with `engine::triggers::list`, copy config from its schema, and confirm the binding fires with a real call (e.g. `web::fetch` to its local URL).

**6. Handy workers.**
- `web::fetch` — all HTTP(S); pass `format: "markdown"` to read docs without flooding context
- `coder::*` — file ops for any code task (read/search/create/update/move/delete)
- `slack::*` — post to Slack

**7. Authoring a worker.** Read the SDK reference for your language first (Node / Python / Rust / Browser / Engine WS) at https://iii.dev/docs/reference/. Use the SDK's `registerWorker(...)` and call `iii.registerFunction` / `iii.registerTrigger` / `iii.trigger` on the returned value; they are methods, not top-level exports. Always declare `description`, `request_format`, and `response_format` so the next caller gets a real contract.

TL;DR: list, info, call. The engine tells you the truth; trust it over memory.

## Configuration

The `harness` configuration entry is owned by the `configuration` worker; every
field hot-reloads (no restart). The fields a deployment is most likely to tune:

```yaml
default_max_turns: 16            # per-turn generate-step cap when a send omits it
default_pending_timeout_ms: 1800000  # legacy parked-call (hold / pre-deploy child) wait guard
max_depth: 3                     # sub-agent depth budget
max_children: 8                  # sub-agent spawns-per-turn budget
max_transient_resumes: 1         # recovery generations after a partial stream failure
projects_file_path: ./data/harness-projects.json  # durable operator project catalog
sweep_expression: "0 * * * * *"  # cron for the pending-call expiry sweep
```

Other keys (RPC timeouts, stream coalescing, idempotency TTL, validation
retries) and their defaults live in [`src/config.rs`](src/config.rs).

## System prompt

The identity prompt is assembled once at send/spawn time. EVERY agent —
top-level turns (`harness::send`) and spawned children alike — is seeded with
the same single identity
([`prompts/default.txt`](prompts/default.txt)): a deliberately minimal prompt
carrying only the basic engine functions and the discovery loop (list, info,
call). A `default` entry in the directory's system-prompt store
(`<skills_folder>/system-prompts/default.md`, served by
`directory::system-prompts::get`) overrides the embedded prompt for every new
composition — write it with `directory::system-prompts::create { name:
"default" }` the first time and `::update` after (or edit the file directly; no
console surface authors it) and the next send picks that up, no restart;
any store failure (directory absent, entry missing, blank body) falls back to
the embedded prompt. What makes a child a leaf is its POLICY, not its prompt: children are
capability-walled out of the orchestration surface (`harness::spawn`,
`harness::send`, trigger registration) unless spawned with
`options: { orchestrator: true }`; spawn `options.system_prompt` remains the
identity escape hatch.

A spawn may also give its child a display-only identity with
`display: { name, icon?, color? }`. `name` is trimmed, limited to 48 characters,
and becomes the title of a newly created child session; `icon` and `color` are
closed semantic tokens recorded with the child linkage in
`metadata.subagent_display`. These fields never affect routing or execution,
and reusing an existing `session_id` retains that session's original title and
metadata. Icons are `agent`, `code`, `search`, `terminal`, `database`, `test`,
`review`, `docs`, or `design`; colors are `neutral`, `blue`, `purple`, `teal`,
`green`, `amber`, or `rose`.

No prompt prescribes an orchestration process — identity prompts carry tool
guidance only, enforced repo-wide by [`tests/prompts.rs`](tests/prompts.rs).
The opt-in fan-out playbook (parent-owned control plane: pick a medium, arm
notifications, spawn leaves directly, define completion per medium) lives in
[`skills/orchestration.md`](skills/orchestration.md) — paste it into a task
prompt or pass it via `options.system_prompt`.

A non-empty `options.system_prompt` is combined with the built-in
prompt per `options.system_prompt_strategy`: `enrich` (default) appends it to
the built-in prompt, while `override` uses it verbatim. Assembly is tested in
[`src/prompt/tests.rs`](src/prompt/tests.rs).

The resolved prompt is STICKY per session, like `model`/`provider` and the
dispatch policy: a send to an existing session that names neither
`system_prompt` nor `system_prompt_strategy` inherits the prior turn's
resolved prompt verbatim (a prior `disabled` turn's absent prompt inherits
too). Naming either field resolves fresh — an explicit bare
`system_prompt_strategy` (e.g. `"enrich"`) is the reset-to-default escape
hatch. The inherited string is frozen at its original resolution — resend
the prompt fields to re-resolve.

### Agent profiles

`options.agent` on a session-creating `harness::send` names a directory agent
profile (`directory::agents::*`, one markdown file per profile). The harness
resolves it ONCE via `directory::agents::get` and freezes the result onto the
turn: the profile's RESOLVED system prompt — the directory composes `extends`
chains root-first, so `tech-lead` extending the bundled `iii` base arrives as
the full iii doctrine followed by the tech-lead body — IS the session
identity. Nothing built-in sits underneath it and no prefix is added; the
usual per-step runtime context (session id, working directory, policy aid,
skills index, hook injections) follows it. A profile whose `extends` chain does not resolve is refused as an
invalid request with the directory's D415 text. The profile's skill filter
becomes the session's skill selection (an explicit `options.skills` wins), its
`model` and optional provider-native `reasoning_effort` are authoritative for
the session, and — when the send also omits
`options.functions` — the dispatch policy defaults to the configured
`default_functions` baseline instead of deny-all (an identity picked to DO
something must be able to dispatch). The
The frozen name/icon/color/model/effort snapshot is also written to session
metadata for clients that render established sessions. The frozen identity
travels with the prompt-stickiness rule: bare later sends
inherit it, an explicit prompt field sheds it. Refused on an existing
session or combined with either prompt field. Directory edits after
resolution never reach a live session — start a new one to pick them up.

`harness::spawn` takes the same id as a top-level `agent` field: the profile's
resolved prompt is the child's whole identity, its skills/model/effort slot in the same way
(model precedence profile → explicit `model` → parent, without dragging the parent's
provider onto a foreign model), and its name and icon become the display
defaults. Which agent profile a spawn names is the prompt's decision — the profile
body steers it, nothing gates it. Spawning
with `agent` into an already RUNNING session of the caller's own tree merges
the task like any reuse and does not re-apply the profile.

New sessions also freeze a names-and-descriptions-only skill index into the
system-prompt prefix. `options.skills` on `harness::send` or `harness::spawn`
accepts exact skill ids. For a fresh session, omitted or empty means all
model-invocable skills. On an existing new-format session, omission inherits
the previous filter while an explicit empty list resets to all; explicit
changes are rejected while its turn is active.
This is curation, not authorization: the turn's function policy must still
allow `directory::skills::get`, and the function must exist in the live
registry. Skill bodies enter context only when the model calls that function.
Catalog changes are appended as durable user-role corrections, leaving the
frozen prefix unchanged. Legacy sessions keep their already-frozen prompt;
start a new session to apply an id filter to one.

Trusted console surfaces can preview the built-in, selected, frozen skill,
runtime-context, registry-notice, and declarative worker-injection layers with
`harness::system-prompt::get`, without making a model request. When the caller
passes no `selected_prompt` and the session has a turn record, the preview
reports the record's RESOLVED prompt (labeled `session (frozen at send)`) —
the truth for what ran and what the next send inherits — instead of
rebuilding the built-in. Set `default_only: true` to read the exact embedded
Harness default without consulting session or runtime state. Static
`pre_generate` hooks publish their exact contribution as trigger metadata
`inject_prompt`; request-dependent hook functions and compaction are not run
by the read-only preview and may change content when the prompt is sent.

## Custom trigger types

The harness emits two async orchestration trigger types siblings and consumers
bind to, and registers five synchronous hook points operator-trusted siblings
plug into in-path. Bind with the standard two-step pattern.

| Trigger type | Kind | Fires / runs |
|---|---|---|
| `harness::turn-started` | async event | A turn began executing (first loop step). Worker-bindable via direct engine registration only — the agent path (`engine::register_trigger`) refuses harness-internal types in every shape. |
| `harness::turn-completed` | async event | A turn reached a terminal status (`completed` / `cancelled` / `failed`), carrying the result and `terminal: bool` — `false` while the session still owns an armed wake (a one-shot notify), meaning a later turn carries the run's real outcome; consumers finalize a logical exchange only on `terminal: true`. Worker-bindable only, same as above. |
| `harness::hook::pre-turn` | sync hook | First step of a turn, before any model spend. May veto. |
| `harness::hook::pre-generate` | sync hook | After context assembly, before generation. May extend the system prompt, append messages, or veto. A static-only hook may publish its exact contribution as trigger metadata `inject_prompt`; the harness appends it directly and skips the compatibility handler. |
| `harness::hook::post-generate` | sync hook | After the final assistant message. Observe only. |
| `harness::hook::pre-trigger` | sync hook | After the allow/deny policy passes, before the target runs. May deny, hold, or rewrite arguments. |
| `harness::hook::post-trigger` | sync hook | After the target returns, before the result is persisted. May rewrite the result. |

Event configs accept `{ session_id?, parent_session_id? }`; hook configs accept
`{ functions?, priority?, timeout_ms?, on_error? }`. See the spec at
[`tech-specs/2026-06-agentic/harness.md`](https://github.com/iii-hq/workers/blob/main/tech-specs/2026-06-agentic/harness.md)
for the hook contract and chain semantics.

## api reference

```json
{
  "functions": [
    {
      "description": "Internal control-plane: edit a still-parked queued message in place by entry_id, preserving its queue position.",
      "metadata": {
        "internal": true
      },
      "name": "harness::edit_queued",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "entry_id": {
            "description": "The queued row to edit (its client-visible `entry_id`).",
            "type": "string"
          },
          "message": {
            "description": "The replacement user message text.",
            "type": "string"
          },
          "session_id": {
            "type": "string"
          }
        },
        "required": [
          "entry_id",
          "message",
          "session_id"
        ],
        "title": "EditQueuedRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "updated": {
            "description": "False when no still-parked row matched — already drained or unknown.",
            "type": "boolean"
          }
        },
        "required": [
          "updated"
        ],
        "title": "EditQueuedResponse",
        "type": "object"
      }
    },
    {
      "description": "Internal control-plane: grant a session access to an additional filesystem root.",
      "metadata": {
        "internal": true
      },
      "name": "harness::filesystem::grant",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "root": {
            "type": "string"
          },
          "session_id": {
            "type": "string"
          }
        },
        "required": [
          "root",
          "session_id"
        ],
        "title": "FilesystemGrantRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "roots": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "session_id": {
            "type": "string"
          }
        },
        "required": [
          "roots",
          "session_id"
        ],
        "title": "FilesystemGrantsResponse",
        "type": "object"
      }
    },
    {
      "description": "Internal control-plane: list additional filesystem roots granted to a session.",
      "metadata": {
        "internal": true
      },
      "name": "harness::filesystem::grants",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "session_id": {
            "type": "string"
          }
        },
        "required": [
          "session_id"
        ],
        "title": "FilesystemGrantsRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "roots": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "session_id": {
            "type": "string"
          }
        },
        "required": [
          "roots",
          "session_id"
        ],
        "title": "FilesystemGrantsResponse",
        "type": "object"
      }
    },
    {
      "description": "Internal control-plane: the default working-directory root new sessions are scoped to.",
      "metadata": {
        "internal": true
      },
      "name": "harness::filesystem::info",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "title": "FilesystemInfoRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "FilesystemBoundary": {
            "enum": [
              "workspace",
              "configured_roots"
            ],
            "type": "string"
          }
        },
        "properties": {
          "boundary": {
            "allOf": [
              {
                "$ref": "#/definitions/FilesystemBoundary"
              }
            ],
            "description": "Effective per-session boundary for shell/coder calls. `workspace` when the filesystem approval hook can widen it, otherwise `configured_roots`."
          },
          "default_root": {
            "description": "Working-directory root stamped onto the first turn of a session whose send carries no explicit `fs_scope.root`; `null` when defaulting is disabled (`default_filesystem_root: \"off\"`) or the cwd is unreadable.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "boundary"
        ],
        "title": "FilesystemInfoResponse",
        "type": "object"
      }
    },
    {
      "description": "Internal control-plane: revoke a session's access to an additional filesystem root.",
      "metadata": {
        "internal": true
      },
      "name": "harness::filesystem::revoke",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "root": {
            "type": "string"
          },
          "session_id": {
            "type": "string"
          }
        },
        "required": [
          "root",
          "session_id"
        ],
        "title": "FilesystemRevokeRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "roots": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "session_id": {
            "type": "string"
          }
        },
        "required": [
          "roots",
          "session_id"
        ],
        "title": "FilesystemGrantsResponse",
        "type": "object"
      }
    },
    {
      "description": "Internal: settle a pending call's result (or release a held call) and resume the parked turn.",
      "metadata": {
        "internal": true
      },
      "name": "harness::function::resolve",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "ContentBlock": {
            "oneOf": [
              {
                "properties": {
                  "text": {
                    "type": "string"
                  },
                  "type": {
                    "enum": [
                      "text"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "text",
                  "type"
                ],
                "type": "object"
              },
              {
                "properties": {
                  "data": {
                    "type": "string"
                  },
                  "mime": {
                    "type": "string"
                  },
                  "type": {
                    "enum": [
                      "image"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "data",
                  "mime",
                  "type"
                ],
                "type": "object"
              },
              {
                "properties": {
                  "signature": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "text": {
                    "type": "string"
                  },
                  "type": {
                    "enum": [
                      "thinking"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "text",
                  "type"
                ],
                "type": "object"
              },
              {
                "description": "Opaque redacted thinking payload — replayed verbatim on the wire.",
                "properties": {
                  "data": {
                    "type": "string"
                  },
                  "type": {
                    "enum": [
                      "redacted_thinking"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "data",
                  "type"
                ],
                "type": "object"
              },
              {
                "properties": {
                  "arguments": true,
                  "function_id": {
                    "type": "string"
                  },
                  "id": {
                    "type": "string"
                  },
                  "type": {
                    "enum": [
                      "function_call"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "arguments",
                  "function_id",
                  "id",
                  "type"
                ],
                "type": "object"
              },
              {
                "properties": {
                  "content": {
                    "items": {
                      "$ref": "#/definitions/ContentBlock"
                    },
                    "type": "array"
                  },
                  "function_call_id": {
                    "type": "string"
                  },
                  "is_error": {
                    "type": [
                      "boolean",
                      "null"
                    ]
                  },
                  "type": {
                    "enum": [
                      "function_result"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "content",
                  "function_call_id",
                  "type"
                ],
                "type": "object"
              }
            ]
          },
          "ResolveFsScope": {
            "properties": {
              "grants": {
                "default": [],
                "items": {
                  "type": "string"
                },
                "type": "array"
              }
            },
            "type": "object"
          }
        },
        "properties": {
          "action": {
            "description": "`deliver` (default) supplies the result; `execute` releases a hook-held call through the remaining trigger pipeline.",
            "type": [
              "string",
              "null"
            ]
          },
          "content": {
            "items": {
              "$ref": "#/definitions/ContentBlock"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "details": true,
          "fs_scope": {
            "anyOf": [
              {
                "$ref": "#/definitions/ResolveFsScope"
              },
              {
                "type": "null"
              }
            ],
            "description": "execute only: one-shot additional roots trusted by the caller and unioned with the session's durable filesystem grants."
          },
          "function_call_id": {
            "type": "string"
          },
          "is_error": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "session_id": {
            "type": "string"
          },
          "turn_id": {
            "type": "string"
          }
        },
        "required": [
          "function_call_id",
          "session_id",
          "turn_id"
        ],
        "title": "FunctionResolveRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "resolved": {
            "description": "False when the call is unknown, already done, or (execute) not held.",
            "type": "boolean"
          },
          "turn_resumed": {
            "description": "True when this resolve re-enqueued the turn.",
            "type": "boolean"
          }
        },
        "required": [
          "resolved",
          "turn_resumed"
        ],
        "title": "FunctionResolveResponse",
        "type": "object"
      }
    },
    {
      "description": "Internal: invoke one iii function (unwrapped from agent_trigger), enforce the dispatch policy, and capture the normalised result — or report it pending.",
      "metadata": {
        "internal": true
      },
      "name": "harness::function::trigger",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "TriggerCall": {
            "properties": {
              "arguments": true,
              "function_id": {
                "description": "The iii function to invoke (already unwrapped from `agent_trigger`).",
                "type": "string"
              },
              "id": {
                "description": "function_call id, echoed into the result.",
                "type": "string"
              }
            },
            "required": [
              "arguments",
              "function_id",
              "id"
            ],
            "type": "object"
          }
        },
        "properties": {
          "call": {
            "$ref": "#/definitions/TriggerCall"
          },
          "session_id": {
            "type": "string"
          }
        },
        "required": [
          "call",
          "session_id"
        ],
        "title": "FunctionTriggerRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "anyOf": [
          {
            "$ref": "#/definitions/TriggerResultResponse"
          },
          {
            "$ref": "#/definitions/TriggerPendingResponse"
          }
        ],
        "definitions": {
          "ContentBlock": {
            "oneOf": [
              {
                "properties": {
                  "text": {
                    "type": "string"
                  },
                  "type": {
                    "enum": [
                      "text"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "text",
                  "type"
                ],
                "type": "object"
              },
              {
                "properties": {
                  "data": {
                    "type": "string"
                  },
                  "mime": {
                    "type": "string"
                  },
                  "type": {
                    "enum": [
                      "image"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "data",
                  "mime",
                  "type"
                ],
                "type": "object"
              },
              {
                "properties": {
                  "signature": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "text": {
                    "type": "string"
                  },
                  "type": {
                    "enum": [
                      "thinking"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "text",
                  "type"
                ],
                "type": "object"
              },
              {
                "description": "Opaque redacted thinking payload — replayed verbatim on the wire.",
                "properties": {
                  "data": {
                    "type": "string"
                  },
                  "type": {
                    "enum": [
                      "redacted_thinking"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "data",
                  "type"
                ],
                "type": "object"
              },
              {
                "properties": {
                  "arguments": true,
                  "function_id": {
                    "type": "string"
                  },
                  "id": {
                    "type": "string"
                  },
                  "type": {
                    "enum": [
                      "function_call"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "arguments",
                  "function_id",
                  "id",
                  "type"
                ],
                "type": "object"
              },
              {
                "properties": {
                  "content": {
                    "items": {
                      "$ref": "#/definitions/ContentBlock"
                    },
                    "type": "array"
                  },
                  "function_call_id": {
                    "type": "string"
                  },
                  "is_error": {
                    "type": [
                      "boolean",
                      "null"
                    ]
                  },
                  "type": {
                    "enum": [
                      "function_result"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "content",
                  "function_call_id",
                  "type"
                ],
                "type": "object"
              }
            ]
          },
          "TriggerPendingResponse": {
            "properties": {
              "function_call_id": {
                "type": "string"
              },
              "function_id": {
                "type": "string"
              },
              "pending": {
                "type": "boolean"
              },
              "pending_timeout_ms": {
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              }
            },
            "required": [
              "function_call_id",
              "function_id",
              "pending"
            ],
            "type": "object"
          },
          "TriggerResultResponse": {
            "properties": {
              "content": {
                "items": {
                  "$ref": "#/definitions/ContentBlock"
                },
                "type": "array"
              },
              "details": true,
              "duration_ms": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "function_call_id": {
                "type": "string"
              },
              "function_id": {
                "type": "string"
              },
              "is_error": {
                "type": "boolean"
              }
            },
            "required": [
              "content",
              "details",
              "duration_ms",
              "function_call_id",
              "function_id",
              "is_error"
            ],
            "type": "object"
          }
        },
        "title": "FunctionTriggerResponse"
      }
    },
    {
      "description": "Aggregate durable model usage, function outcomes, and available trace/span observability. `complete` is true only after every session in the durable tree has reached a terminal turn.",
      "metadata": {},
      "name": "harness::metrics",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "root_session_id": {
            "type": "string"
          }
        },
        "required": [
          "root_session_id"
        ],
        "title": "SessionMetricsRequestV1",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "definitions": {
          "ContextSnapshotV1": {
            "description": "One generation's context accounting. `free = usable - total`, floored at zero: once provider usage lands, `total` is what was billed, which can exceed the `usable` budget the window was fit into — that budget was derived before the generation from an estimate.",
            "properties": {
              "categories": {
                "$ref": "#/definitions/SnapshotCategoriesV1"
              },
              "compacted": {
                "type": "boolean"
              },
              "effective_max_output_tokens": {
                "description": "Output allocation `usable` was derived against.",
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "estimator": {
                "description": "Which estimator produced the numbers (`heuristic` until the context-manager resolves a real tokenizer). Absent when the context-manager predates the breakdown response.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "free": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "model": {
                "type": "string"
              },
              "provider": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "session_cost_usd": {
                "description": "Running cost of the whole session in USD, accumulated across every generation step. `usage.cost_usd` is one step's bill — on providers with steep cache discounts the per-step number swings two orders of magnitude, so a chip showing it alone reads as a bouncing total.",
                "format": "double",
                "type": [
                  "number",
                  "null"
                ]
              },
              "session_id": {
                "type": "string"
              },
              "step": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "summarized_head_tokens": {
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "timestamp": {
                "format": "int64",
                "type": "integer"
              },
              "total": {
                "description": "Final request estimate: categories plus post-assembly growth.",
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "turn_id": {
                "type": "string"
              },
              "usable": {
                "description": "The input budget the window was fit into.",
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "usage": {
                "anyOf": [
                  {
                    "$ref": "#/definitions/Usage"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Actual provider usage for this generation, stamped after the terminal frame; absent when the provider returned none (or the generation never completed)."
              }
            },
            "required": [
              "categories",
              "compacted",
              "effective_max_output_tokens",
              "free",
              "model",
              "session_id",
              "step",
              "timestamp",
              "total",
              "turn_id",
              "usable"
            ],
            "type": "object"
          },
          "SessionTraceMetricsV1": {
            "additionalProperties": false,
            "properties": {
              "by_session": {
                "items": {
                  "$ref": "#/definitions/SessionTraceUsageV1"
                },
                "type": "array"
              },
              "duration_ms": {
                "description": "Elapsed window from the first observed span to the last observed span.",
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "error_span_count": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "span_count": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "trace_count": {
                "description": "Distinct traces across the root session and all descendants.",
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              }
            },
            "required": [
              "by_session",
              "duration_ms",
              "error_span_count",
              "span_count",
              "trace_count"
            ],
            "type": "object"
          },
          "SessionTraceUsageV1": {
            "additionalProperties": false,
            "properties": {
              "depth": {
                "format": "uint32",
                "minimum": 0,
                "type": "integer"
              },
              "duration_ms": {
                "description": "Elapsed window from the session's first observed span to its last.",
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "error_span_count": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "parent_session_id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "session_id": {
                "type": "string"
              },
              "span_count": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "trace_count": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              }
            },
            "required": [
              "depth",
              "duration_ms",
              "error_span_count",
              "session_id",
              "span_count",
              "trace_count"
            ],
            "type": "object"
          },
          "SessionUsageTotalsV1": {
            "additionalProperties": false,
            "properties": {
              "cache_read_tokens": {
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "cache_write_tokens": {
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "cost_usd": {
                "format": "double",
                "type": [
                  "number",
                  "null"
                ]
              },
              "function_call_errors": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "function_calls": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "input_tokens": {
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "output_tokens": {
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "reasoning_tokens": {
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "sessions": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "turns": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              }
            },
            "required": [
              "function_call_errors",
              "function_calls",
              "sessions",
              "turns"
            ],
            "type": "object"
          },
          "SessionUsageV1": {
            "additionalProperties": false,
            "properties": {
              "cache_read_tokens": {
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "cache_write_tokens": {
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "context": {
                "anyOf": [
                  {
                    "$ref": "#/definitions/ContextSnapshotV1"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "The session's latest per-generation context snapshot (categories, budget, usage) — absent for sessions that have not generated since snapshots landed."
              },
              "cost_usd": {
                "format": "double",
                "type": [
                  "number",
                  "null"
                ]
              },
              "depth": {
                "format": "uint32",
                "minimum": 0,
                "type": "integer"
              },
              "function_call_errors": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "function_calls": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "input_tokens": {
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "output_tokens": {
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "parent_session_id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "reasoning_tokens": {
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "session_id": {
                "type": "string"
              },
              "turns": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              }
            },
            "required": [
              "depth",
              "function_call_errors",
              "function_calls",
              "session_id",
              "turns"
            ],
            "type": "object"
          },
          "SnapshotCategoriesV1": {
            "description": "Where the request's tokens sit. Categories are assembly-time estimates; `hook_guidance` is the measured growth after assembly (pre-generate hook appends and orphan-repair patches), 0 when the request left assembly unchanged.",
            "properties": {
              "hook_guidance": {
                "default": 0,
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "messages": {
                "$ref": "#/definitions/SnapshotMessagesV1"
              },
              "overhead": {
                "description": "Provider framing plus response_format / provider_options fields.",
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "skills": {
                "default": 0,
                "description": "Selected skill bodies contained in the system prompt.",
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "system_prompt": {
                "description": "Final assembled system prompt excluding tokens attributed to `skills`: identity, per-step aids, and any compaction summary section.",
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "tools": {
                "description": "Function schemas exposed to the model.",
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              }
            },
            "required": [
              "messages",
              "overhead",
              "system_prompt",
              "tools"
            ],
            "type": "object"
          },
          "SnapshotMessagesV1": {
            "description": "Estimated tokens of the assembled window's messages, by role.",
            "properties": {
              "assistant": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "custom": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "function_result": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "user": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              }
            },
            "required": [
              "assistant",
              "custom",
              "function_result",
              "user"
            ],
            "type": "object"
          },
          "Usage": {
            "properties": {
              "cache_read": {
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "cache_write": {
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "cost_usd": {
                "format": "double",
                "type": [
                  "number",
                  "null"
                ]
              },
              "input": {
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "output": {
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "reasoning": {
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              }
            },
            "type": "object"
          }
        },
        "properties": {
          "by_session": {
            "items": {
              "$ref": "#/definitions/SessionUsageV1"
            },
            "type": "array"
          },
          "complete": {
            "type": "boolean"
          },
          "root_session_id": {
            "type": "string"
          },
          "totals": {
            "$ref": "#/definitions/SessionUsageTotalsV1"
          },
          "traces": {
            "anyOf": [
              {
                "$ref": "#/definitions/SessionTraceMetricsV1"
              },
              {
                "type": "null"
              }
            ],
            "description": "Trace/span aggregates when the engine's in-memory observability exporter is available. Usage metrics remain available when it is not."
          }
        },
        "required": [
          "by_session",
          "complete",
          "root_session_id",
          "totals"
        ],
        "title": "SessionMetricsResponseV1",
        "type": "object"
      }
    },
    {
      "description": "Internal: refresh the cached function-registry snapshot when functions are registered/unregistered (driven by the engine::functions-available trigger).",
      "metadata": {
        "internal": true
      },
      "name": "harness::on-functions-change",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "description": "Internal `harness::on-functions-change` payload. The handler re-fetches the authoritative registry, so the (advisory) event tag is the only field.",
        "properties": {
          "event": {
            "default": null,
            "description": "Engine event tag (advisory; the handler re-fetches the full list).",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "title": "OnFunctionsChangeEvent",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "description": "Ack returned by the internal `harness::on-functions-change` handler.",
        "properties": {
          "ok": {
            "type": "boolean"
          }
        },
        "required": [
          "ok"
        ],
        "title": "OnFunctionsChangeResponse",
        "type": "object"
      }
    },
    {
      "description": "Internal: drop a deleted session's ephemeral subscriptions. Not called directly.",
      "metadata": {
        "internal": true
      },
      "name": "harness::on-session-deleted",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "description": "`session::deleted` payload (only the field we read).",
        "properties": {
          "session_id": {
            "type": "string"
          }
        },
        "required": [
          "session_id"
        ],
        "title": "SessionDeletedEvent",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "removed": {
            "format": "uint64",
            "minimum": 0,
            "type": "integer"
          }
        },
        "required": [
          "ok",
          "removed"
        ],
        "title": "SessionDeletedAck",
        "type": "object"
      }
    },
    {
      "description": "Internal: refresh the cached model-invocable skill catalog.",
      "metadata": {
        "internal": true
      },
      "name": "harness::on-skills-change",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "op": {
            "default": null,
            "type": [
              "string",
              "null"
            ]
          }
        },
        "title": "OnSkillsChangeEvent",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "ok": {
            "type": "boolean"
          }
        },
        "required": [
          "ok"
        ],
        "title": "OnSkillsChangeResponse",
        "type": "object"
      }
    },
    {
      "description": "Internal control-plane: remove a project directory from the durable catalog.",
      "metadata": {
        "internal": true
      },
      "name": "harness::projects::delete",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "path": {
            "type": "string"
          }
        },
        "required": [
          "path"
        ],
        "title": "ProjectDeleteRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "deleted": {
            "type": "boolean"
          }
        },
        "required": [
          "deleted"
        ],
        "title": "ProjectDeleteResponse",
        "type": "object"
      }
    },
    {
      "description": "Internal control-plane: list the operator's durable project catalog.",
      "metadata": {
        "internal": true
      },
      "name": "harness::projects::list",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "title": "ProjectsListRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "Project": {
            "properties": {
              "last_used_at": {
                "format": "int64",
                "type": "integer"
              },
              "name": {
                "type": "string"
              },
              "path": {
                "type": "string"
              }
            },
            "required": [
              "last_used_at",
              "name",
              "path"
            ],
            "type": "object"
          }
        },
        "properties": {
          "projects": {
            "items": {
              "$ref": "#/definitions/Project"
            },
            "type": "array"
          }
        },
        "required": [
          "projects"
        ],
        "title": "ProjectsListResponse",
        "type": "object"
      }
    },
    {
      "description": "Internal control-plane: remember, touch, or rename a project directory.",
      "metadata": {
        "internal": true
      },
      "name": "harness::projects::upsert",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "name": {
            "default": null,
            "description": "A custom display name. Omit to keep the current name (or use the folder name for a new project); pass blank to reset to the folder name.",
            "type": [
              "string",
              "null"
            ]
          },
          "path": {
            "type": "string"
          }
        },
        "required": [
          "path"
        ],
        "title": "ProjectUpsertRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "Project": {
            "properties": {
              "last_used_at": {
                "format": "int64",
                "type": "integer"
              },
              "name": {
                "type": "string"
              },
              "path": {
                "type": "string"
              }
            },
            "required": [
              "last_used_at",
              "name",
              "path"
            ],
            "type": "object"
          }
        },
        "properties": {
          "project": {
            "$ref": "#/definitions/Project"
          }
        },
        "required": [
          "project"
        ],
        "title": "ProjectUpsertResponse",
        "type": "object"
      }
    },
    {
      "description": "Entry point: ensure the session, persist the incoming message, and kick off a turn; returns fast (or merges into a running turn).",
      "metadata": {
        "internal": true
      },
      "name": "harness::send",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "ExposeMode": {
            "description": "How allowed functions reach the model (harness.md § Exposure modes).",
            "enum": [
              "agent_trigger",
              "native"
            ],
            "type": "string"
          },
          "FunctionPolicy": {
            "description": "The fail-closed dispatch policy (harness.md § Functions). Absent on the send => every call denied (a plain chat loop).",
            "properties": {
              "allow": {
                "default": [],
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              "deny": {
                "default": [],
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              "expose": {
                "allOf": [
                  {
                    "$ref": "#/definitions/ExposeMode"
                  }
                ],
                "default": "agent_trigger"
              }
            },
            "type": "object"
          },
          "OutputContract": {
            "description": "Free text by default; `json` constrains the final answer to a JSON value, validated against `schema` when supplied.",
            "oneOf": [
              {
                "properties": {
                  "type": {
                    "enum": [
                      "text"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "type"
                ],
                "type": "object"
              },
              {
                "properties": {
                  "schema": true,
                  "type": {
                    "enum": [
                      "json"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "type"
                ],
                "type": "object"
              }
            ]
          },
          "SendOptions": {
            "description": "Per-send options frozen onto the turn record (harness.md § `harness::send`).",
            "properties": {
              "agent": {
                "description": "Directory agent profile id (`directory::agents::*`) replacing the built-in identity; new sessions only, refused with a prompt field.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "functions": {
                "anyOf": [
                  {
                    "$ref": "#/definitions/FunctionPolicy"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Fail-closed dispatch policy; omitted means deny all on a new session and inherit on an existing one (`{ allow: [] }` strips explicitly)."
              },
              "max_cost_usd": {
                "description": "Hard USD budget for the complete root-and-subagent session tree. Every model used by the tree must advertise catalog pricing.",
                "format": "double",
                "type": [
                  "number",
                  "null"
                ]
              },
              "max_output_tokens": {
                "description": "Per-generation output-token ceiling forwarded to the router.",
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "max_total_tokens": {
                "description": "Hard input-plus-output token budget for the complete root-and-subagent session tree.",
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "max_turns": {
                "format": "uint32",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "max_validation_retries": {
                "description": "Per-turn override of the validation-retry budget.",
                "format": "uint32",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "metadata": {
                "description": "Tracing passthrough."
              },
              "output": {
                "anyOf": [
                  {
                    "$ref": "#/definitions/OutputContract"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "The turn's deliverable; default `{ type: \"text\" }`."
              },
              "provider_options": {
                "additionalProperties": true,
                "description": "Provider-native per-call options, namespaced by provider id.",
                "type": [
                  "object",
                  "null"
                ]
              },
              "skills": {
                "description": "Exact skill ids advertised to the model; omitted or empty means all on a new session (existing: omitted inherits, empty resets).",
                "items": {
                  "type": "string"
                },
                "type": [
                  "array",
                  "null"
                ]
              },
              "system_prompt": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "system_prompt_strategy": {
                "anyOf": [
                  {
                    "$ref": "#/definitions/SystemPromptStrategy"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "How `system_prompt` combines with the built-in prompt; omitting both prompt fields on an existing session inherits the prior prompt."
              },
              "thinking_level": {
                "anyOf": [
                  {
                    "$ref": "#/definitions/ThinkingLevel"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            },
            "type": "object"
          },
          "SessionInit": {
            "description": "Session create/ensure options applied when this send creates the session.",
            "properties": {
              "metadata": true,
              "title": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "type": "object"
          },
          "SystemPromptStrategy": {
            "description": "How a caller-supplied system prompt combines with the built-in identity prompt.",
            "oneOf": [
              {
                "description": "Caller prompt replaces the built-in prompt verbatim.",
                "enum": [
                  "override"
                ],
                "type": "string"
              },
              {
                "description": "Caller prompt is appended to the built-in identity prompt.",
                "enum": [
                  "enrich"
                ],
                "type": "string"
              },
              {
                "description": "No system prompt is sent to the model.",
                "enum": [
                  "disabled"
                ],
                "type": "string"
              }
            ]
          },
          "ThinkingLevel": {
            "enum": [
              "minimal",
              "low",
              "medium",
              "high",
              "xhigh"
            ],
            "type": "string"
          }
        },
        "properties": {
          "idempotency_key": {
            "description": "Webhook dedupe: a repeated key returns the original `{session_id, turn_id}` and appends nothing.",
            "type": [
              "string",
              "null"
            ]
          },
          "message": {
            "description": "The incoming user message text.",
            "type": "string"
          },
          "model": {
            "description": "Required on a new session unless `options.agent` supplies a model; an existing session inherits its last turn's model when omitted.",
            "type": [
              "string",
              "null"
            ]
          },
          "options": {
            "anyOf": [
              {
                "$ref": "#/definitions/SendOptions"
              },
              {
                "type": "null"
              }
            ]
          },
          "provider": {
            "type": [
              "string",
              "null"
            ]
          },
          "session": {
            "anyOf": [
              {
                "$ref": "#/definitions/SessionInit"
              },
              {
                "type": "null"
              }
            ],
            "description": "Applied when this send creates/ensures the session."
          },
          "session_id": {
            "description": "Omit to create a new session.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "message"
        ],
        "title": "SendRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "accepted": {
            "type": "boolean"
          },
          "deduplicated": {
            "description": "True when `idempotency_key` matched an earlier send.",
            "type": [
              "boolean",
              "null"
            ]
          },
          "merged": {
            "description": "True when folded into an in-flight turn (steering).",
            "type": [
              "boolean",
              "null"
            ]
          },
          "queued": {
            "description": "True when the message was queued while a step was streaming; it lands in the transcript when the stream ends.",
            "type": [
              "boolean",
              "null"
            ]
          },
          "session_id": {
            "type": "string"
          },
          "turn_id": {
            "type": "string"
          }
        },
        "required": [
          "accepted",
          "session_id",
          "turn_id"
        ],
        "title": "SendResponse",
        "type": "object"
      }
    },
    {
      "description": "Read the durable root-and-descendant session tree for one harness run.",
      "metadata": {},
      "name": "harness::session-tree",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "root_session_id": {
            "type": "string"
          }
        },
        "required": [
          "root_session_id"
        ],
        "title": "SessionTreeRequestV1",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "definitions": {
          "SessionTreeNodeV1": {
            "additionalProperties": false,
            "properties": {
              "depth": {
                "format": "uint32",
                "minimum": 0,
                "type": "integer"
              },
              "parent_session_id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "parent_turn_id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "session_id": {
                "type": "string"
              }
            },
            "required": [
              "depth",
              "session_id"
            ],
            "type": "object"
          }
        },
        "properties": {
          "complete": {
            "type": "boolean"
          },
          "root_session_id": {
            "type": "string"
          },
          "sessions": {
            "items": {
              "$ref": "#/definitions/SessionTreeNodeV1"
            },
            "type": "array"
          }
        },
        "required": [
          "complete",
          "root_session_id",
          "sessions"
        ],
        "title": "SessionTreeResponseV1",
        "type": "object"
      }
    },
    {
      "description": "Spawn a sub-agent in a child session (never a trigger target) and return { child_session_id, child_turn_id } immediately; the child's outcome reaches you only through whatever destination its task names. Children are leaves unless options.orchestrator is true.",
      "metadata": {},
      "name": "harness::spawn",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "ExposeMode": {
            "description": "How allowed functions reach the model (harness.md § Exposure modes).",
            "enum": [
              "agent_trigger",
              "native"
            ],
            "type": "string"
          },
          "FunctionPolicy": {
            "description": "The fail-closed dispatch policy (harness.md § Functions). Absent on the send => every call denied (a plain chat loop).",
            "properties": {
              "allow": {
                "default": [],
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              "deny": {
                "default": [],
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              "expose": {
                "allOf": [
                  {
                    "$ref": "#/definitions/ExposeMode"
                  }
                ],
                "default": "agent_trigger"
              }
            },
            "type": "object"
          },
          "OutputContract": {
            "description": "Free text by default; `json` constrains the final answer to a JSON value, validated against `schema` when supplied.",
            "oneOf": [
              {
                "properties": {
                  "type": {
                    "enum": [
                      "text"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "type"
                ],
                "type": "object"
              },
              {
                "properties": {
                  "schema": true,
                  "type": {
                    "enum": [
                      "json"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "type"
                ],
                "type": "object"
              }
            ]
          },
          "SpawnOptions": {
            "properties": {
              "filesystem_root": {
                "description": "Absolute filesystem root for the child turn; omit to inherit the parent's.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "functions": {
                "anyOf": [
                  {
                    "$ref": "#/definitions/FunctionPolicy"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Dispatch policy for the child, intersected with the parent's (narrow, never escalate)."
              },
              "max_children": {
                "description": "Fan-out guard for the child's own spawns.",
                "format": "uint32",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "max_output_tokens": {
                "description": "Inherits the parent's ceiling unless explicitly narrowed/overridden.",
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "max_turns": {
                "description": "Turn cap for the child, capped at the parent's remaining budget; omit unless required (small values strand the child).",
                "format": "uint32",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "max_validation_retries": {
                "description": "Override of the child's validation-retry budget.",
                "format": "uint32",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "orchestrator": {
                "description": "Let the child spawn, send, and register triggers (still capped by the parent's policy); default false makes it a leaf.",
                "type": [
                  "boolean",
                  "null"
                ]
              },
              "output": {
                "anyOf": [
                  {
                    "$ref": "#/definitions/OutputContract"
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "The child's deliverable: text / json / json+schema."
              },
              "skills": {
                "description": "Exact skill ids advertised to the child; omitted or empty means all (a reused child inherits when omitted).",
                "items": {
                  "type": "string"
                },
                "type": [
                  "array",
                  "null"
                ]
              },
              "system_prompt": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "system_prompt_strategy": {
                "allOf": [
                  {
                    "$ref": "#/definitions/SystemPromptStrategy"
                  }
                ],
                "default": "enrich",
                "description": "How `system_prompt` combines with the built-in prompt."
              },
              "thinking_level": {
                "anyOf": [
                  {
                    "$ref": "#/definitions/ThinkingLevel"
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            },
            "type": "object"
          },
          "SubagentColor": {
            "enum": [
              "neutral",
              "blue",
              "purple",
              "teal",
              "green",
              "amber",
              "rose"
            ],
            "type": "string"
          },
          "SubagentDisplay": {
            "description": "Display-only identity for a spawned child. The name becomes the session title; icon and color are closed semantic tokens consumed by UIs.",
            "properties": {
              "color": {
                "anyOf": [
                  {
                    "$ref": "#/definitions/SubagentColor"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "icon": {
                "anyOf": [
                  {
                    "$ref": "#/definitions/SubagentIcon"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "name": {
                "description": "Short functional name such as `Frontend`, 1-48 characters after trimming.",
                "maxLength": 48,
                "minLength": 1,
                "type": "string"
              }
            },
            "required": [
              "name"
            ],
            "type": "object"
          },
          "SubagentIcon": {
            "enum": [
              "agent",
              "code",
              "search",
              "terminal",
              "database",
              "test",
              "review",
              "docs",
              "design"
            ],
            "type": "string"
          },
          "SystemPromptStrategy": {
            "description": "How a caller-supplied system prompt combines with the built-in identity prompt.",
            "oneOf": [
              {
                "description": "Caller prompt replaces the built-in prompt verbatim.",
                "enum": [
                  "override"
                ],
                "type": "string"
              },
              {
                "description": "Caller prompt is appended to the built-in identity prompt.",
                "enum": [
                  "enrich"
                ],
                "type": "string"
              },
              {
                "description": "No system prompt is sent to the model.",
                "enum": [
                  "disabled"
                ],
                "type": "string"
              }
            ]
          },
          "ThinkingLevel": {
            "enum": [
              "minimal",
              "low",
              "medium",
              "high",
              "xhigh"
            ],
            "type": "string"
          }
        },
        "properties": {
          "agent": {
            "description": "Directory agent profile id (`directory::agents::*`) supplying the child's prompt, skills, model, and display; refused with `options.system_prompt`.",
            "type": [
              "string",
              "null"
            ]
          },
          "display": {
            "anyOf": [
              {
                "$ref": "#/definitions/SubagentDisplay"
              },
              {
                "type": "null"
              }
            ],
            "description": "Display-only name/icon/color for the child session; never affects ids, policy, or routing."
          },
          "model": {
            "type": [
              "string",
              "null"
            ]
          },
          "options": {
            "anyOf": [
              {
                "$ref": "#/definitions/SpawnOptions"
              },
              {
                "type": "null"
              }
            ]
          },
          "parent_session_id": {
            "description": "Display-only parent for the console tree when there is no live parent turn; grants no policy inheritance.",
            "type": [
              "string",
              "null"
            ]
          },
          "provider": {
            "type": [
              "string",
              "null"
            ]
          },
          "session_id": {
            "description": "Session id to spawn into, created if absent; an existing id may be reused only inside the caller's own tree.",
            "type": [
              "string",
              "null"
            ]
          },
          "task": {
            "description": "The child's self-contained goal, its opening user message; name every required resource selector literally (the child cannot infer them).",
            "type": "string"
          }
        },
        "required": [
          "task"
        ],
        "title": "SpawnRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "child_session_id": {
            "type": "string"
          },
          "child_turn_id": {
            "type": "string"
          },
          "reused": {
            "default": false,
            "description": "The named session already existed and was reused — its prior transcript and parent linkage were retained (only possible with an explicit `session_id`).",
            "type": "boolean"
          }
        },
        "required": [
          "child_session_id",
          "child_turn_id"
        ],
        "title": "SpawnResponse",
        "type": "object"
      }
    },
    {
      "description": "Read the current turn status for a session.",
      "metadata": {},
      "name": "harness::status",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "session_id": {
            "type": "string"
          }
        },
        "required": [
          "session_id"
        ],
        "title": "StatusRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "anyOf": [
          {
            "$ref": "#/definitions/StatusReport"
          },
          {
            "type": "null"
          }
        ],
        "definitions": {
          "AgentMessage": {
            "anyOf": [
              {
                "$ref": "#/definitions/AssistantMessage"
              },
              {
                "$ref": "#/definitions/FunctionResultMessage"
              },
              {
                "$ref": "#/definitions/CustomMessage"
              },
              {
                "$ref": "#/definitions/UserMessage"
              }
            ],
            "description": "The canonical transcript message union. Untagged: the single-variant role tags disambiguate deserialization (assistant/function_result/custom are tried before user so their required fields gate the match)."
          },
          "ArmedWake": {
            "description": "One armed wake as `harness::status` reports it — enough for a console or a poller to say \"parked on state operation_meta/status since T, deadline T2\" instead of showing a session that just looks quietly done.",
            "properties": {
              "config": true,
              "created_at": {
                "format": "int64",
                "type": "integer"
              },
              "expires_at": {
                "format": "int64",
                "type": [
                  "integer",
                  "null"
                ]
              },
              "subscription_id": {
                "type": "string"
              },
              "trigger_type": {
                "description": "The registered trigger's type/config, read from the canonicalised registration request. Absent on records that predate it.",
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "created_at",
              "subscription_id"
            ],
            "type": "object"
          },
          "AssistantMessage": {
            "properties": {
              "content": {
                "items": {
                  "$ref": "#/definitions/ContentBlock"
                },
                "type": "array"
              },
              "error_kind": {
                "anyOf": [
                  {
                    "$ref": "#/definitions/ErrorKind"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "error_message": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "model": {
                "type": "string"
              },
              "native_stop_reason": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "provider": {
                "type": "string"
              },
              "role": {
                "$ref": "#/definitions/AssistantRoleTag"
              },
              "stop_reason": {
                "$ref": "#/definitions/StopReason"
              },
              "timestamp": {
                "format": "int64",
                "type": "integer"
              },
              "usage": {
                "anyOf": [
                  {
                    "$ref": "#/definitions/Usage"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "warnings": {
                "items": {
                  "type": "string"
                },
                "type": [
                  "array",
                  "null"
                ]
              }
            },
            "required": [
              "content",
              "model",
              "provider",
              "role",
              "stop_reason",
              "timestamp"
            ],
            "type": "object"
          },
          "AssistantRoleTag": {
            "enum": [
              "assistant"
            ],
            "type": "string"
          },
          "ChildRef": {
            "properties": {
              "function_call_id": {
                "type": "string"
              },
              "session_id": {
                "type": "string"
              },
              "turn_id": {
                "type": "string"
              }
            },
            "required": [
              "function_call_id",
              "session_id",
              "turn_id"
            ],
            "type": "object"
          },
          "ContentBlock": {
            "oneOf": [
              {
                "properties": {
                  "text": {
                    "type": "string"
                  },
                  "type": {
                    "enum": [
                      "text"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "text",
                  "type"
                ],
                "type": "object"
              },
              {
                "properties": {
                  "data": {
                    "type": "string"
                  },
                  "mime": {
                    "type": "string"
                  },
                  "type": {
                    "enum": [
                      "image"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "data",
                  "mime",
                  "type"
                ],
                "type": "object"
              },
              {
                "properties": {
                  "signature": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "text": {
                    "type": "string"
                  },
                  "type": {
                    "enum": [
                      "thinking"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "text",
                  "type"
                ],
                "type": "object"
              },
              {
                "description": "Opaque redacted thinking payload — replayed verbatim on the wire.",
                "properties": {
                  "data": {
                    "type": "string"
                  },
                  "type": {
                    "enum": [
                      "redacted_thinking"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "data",
                  "type"
                ],
                "type": "object"
              },
              {
                "properties": {
                  "arguments": true,
                  "function_id": {
                    "type": "string"
                  },
                  "id": {
                    "type": "string"
                  },
                  "type": {
                    "enum": [
                      "function_call"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "arguments",
                  "function_id",
                  "id",
                  "type"
                ],
                "type": "object"
              },
              {
                "properties": {
                  "content": {
                    "items": {
                      "$ref": "#/definitions/ContentBlock"
                    },
                    "type": "array"
                  },
                  "function_call_id": {
                    "type": "string"
                  },
                  "is_error": {
                    "type": [
                      "boolean",
                      "null"
                    ]
                  },
                  "type": {
                    "enum": [
                      "function_result"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "content",
                  "function_call_id",
                  "type"
                ],
                "type": "object"
              }
            ]
          },
          "CustomMessage": {
            "properties": {
              "content": {
                "items": {
                  "$ref": "#/definitions/ContentBlock"
                },
                "type": "array"
              },
              "custom_type": {
                "type": "string"
              },
              "details": true,
              "display": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "role": {
                "$ref": "#/definitions/CustomRoleTag"
              },
              "timestamp": {
                "format": "int64",
                "type": "integer"
              }
            },
            "required": [
              "content",
              "custom_type",
              "role",
              "timestamp"
            ],
            "type": "object"
          },
          "CustomRoleTag": {
            "enum": [
              "custom"
            ],
            "type": "string"
          },
          "ErrorKind": {
            "enum": [
              "auth_expired",
              "rate_limited",
              "context_overflow",
              "transient",
              "permanent"
            ],
            "type": "string"
          },
          "FunctionResultMessage": {
            "properties": {
              "content": {
                "items": {
                  "$ref": "#/definitions/ContentBlock"
                },
                "type": "array"
              },
              "details": true,
              "function_call_id": {
                "type": "string"
              },
              "function_id": {
                "type": "string"
              },
              "is_error": {
                "type": "boolean"
              },
              "role": {
                "$ref": "#/definitions/FunctionResultRoleTag"
              },
              "timestamp": {
                "format": "int64",
                "type": "integer"
              }
            },
            "required": [
              "content",
              "details",
              "function_call_id",
              "function_id",
              "is_error",
              "role",
              "timestamp"
            ],
            "type": "object"
          },
          "FunctionResultRoleTag": {
            "enum": [
              "function_result"
            ],
            "type": "string"
          },
          "QueuedMessage": {
            "description": "One message parked while a step was streaming, waiting for the loop's drain to append it to the transcript (harness.md § Concurrency & steering).",
            "properties": {
              "entry_id": {
                "description": "Deterministic transcript entry id the drain appends under, so a redelivered drain is a no-op.",
                "type": "string"
              },
              "id": {
                "type": "string"
              },
              "message": {
                "$ref": "#/definitions/AgentMessage"
              },
              "origin": true,
              "queued_at": {
                "format": "int64",
                "type": "integer"
              },
              "session_id": {
                "type": "string"
              }
            },
            "required": [
              "entry_id",
              "id",
              "message",
              "queued_at",
              "session_id"
            ],
            "type": "object"
          },
          "StatusReport": {
            "properties": {
              "armed_wakes": {
                "description": "WHAT the session is parked on, when `expects_wake`: each armed wake's watch and deadline, so \"parked 12m on state operation_meta/status — never written\" is readable from the outside instead of the session just looking quietly done.",
                "items": {
                  "$ref": "#/definitions/ArmedWake"
                },
                "type": "array"
              },
              "children": {
                "items": {
                  "$ref": "#/definitions/ChildRef"
                },
                "type": "array"
              },
              "depth": {
                "format": "uint32",
                "minimum": 0,
                "type": "integer"
              },
              "expects_wake": {
                "default": false,
                "description": "The session owns an armed wake (a one-shot notify subscription): a completed turn here is NOT the run's outcome — a later turn in this session carries it. Mirrors the `terminal` flag on `harness::turn-completed` (`expects_wake == !terminal`). Pollers (e.g. workflow reconcile) must treat `completed && expects_wake` as still running.",
                "type": "boolean"
              },
              "max_transient_resumes": {
                "format": "uint32",
                "minimum": 0,
                "type": "integer"
              },
              "max_turns": {
                "format": "uint32",
                "minimum": 0,
                "type": "integer"
              },
              "max_validation_retries": {
                "format": "uint32",
                "minimum": 0,
                "type": "integer"
              },
              "partial_result_available": {
                "type": "boolean"
              },
              "pending_function_calls": {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              "queued": {
                "description": "Messages queued while a step streams, in arrival order; they land in the transcript when the stream ends.",
                "items": {
                  "$ref": "#/definitions/QueuedMessage"
                },
                "type": "array"
              },
              "result": true,
              "result_error": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "session_id": {
                "type": "string"
              },
              "status": {
                "$ref": "#/definitions/TurnStatus"
              },
              "step": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "transient_resumes": {
                "format": "uint32",
                "minimum": 0,
                "type": "integer"
              },
              "turn_count": {
                "format": "uint32",
                "minimum": 0,
                "type": "integer"
              },
              "turn_id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "validation_retries": {
                "format": "uint32",
                "minimum": 0,
                "type": "integer"
              }
            },
            "required": [
              "children",
              "depth",
              "max_transient_resumes",
              "max_turns",
              "max_validation_retries",
              "partial_result_available",
              "pending_function_calls",
              "session_id",
              "status",
              "step",
              "transient_resumes",
              "turn_count",
              "validation_retries"
            ],
            "type": "object"
          },
          "StopReason": {
            "enum": [
              "end",
              "length",
              "function_call",
              "aborted",
              "error"
            ],
            "type": "string"
          },
          "TurnStatus": {
            "description": "The coarse, harness-internal turn lifecycle (harness.md § API Reference). Finer-grained than the session's `status`, which the loop derives from it.",
            "enum": [
              "running",
              "awaiting_functions",
              "completed",
              "cancelled",
              "failed"
            ],
            "type": "string"
          },
          "Usage": {
            "properties": {
              "cache_read": {
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "cache_write": {
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "cost_usd": {
                "format": "double",
                "type": [
                  "number",
                  "null"
                ]
              },
              "input": {
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "output": {
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "reasoning": {
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              }
            },
            "type": "object"
          },
          "UserMessage": {
            "properties": {
              "content": {
                "items": {
                  "$ref": "#/definitions/ContentBlock"
                },
                "type": "array"
              },
              "role": {
                "$ref": "#/definitions/UserRoleTag"
              },
              "timestamp": {
                "format": "int64",
                "type": "integer"
              }
            },
            "required": [
              "content",
              "role",
              "timestamp"
            ],
            "type": "object"
          },
          "UserRoleTag": {
            "enum": [
              "user"
            ],
            "type": "string"
          }
        },
        "title": "Nullable_StatusReport"
      }
    },
    {
      "description": "Request cancellation of an in-flight turn (cascades to spawned children).",
      "metadata": {
        "internal": true
      },
      "name": "harness::stop",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "session_id": {
            "type": "string"
          },
          "turn_id": {
            "description": "Omit to stop the current turn.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "session_id"
        ],
        "title": "StopRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "stopping": {
            "type": "boolean"
          }
        },
        "required": [
          "stopping"
        ],
        "title": "StopResponse",
        "type": "object"
      }
    },
    {
      "description": "Internal cron sweep: resolve pending function calls past their timeout so a parked turn never wedges. Not called directly.",
      "metadata": {
        "internal": true
      },
      "name": "harness::sweep-pending",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "description": "Cron event payload (ignored — the sweep scans all turn records). A struct keeps the request schema concrete.",
        "properties": {
          "scheduled_at": {
            "default": null,
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "title": "SweepEvent",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "resolved": {
            "description": "Number of expired pending calls resolved this sweep.",
            "format": "uint64",
            "minimum": 0,
            "type": "integer"
          }
        },
        "required": [
          "ok",
          "resolved"
        ],
        "title": "SweepResponse",
        "type": "object"
      }
    },
    {
      "description": "Preview the system prompt layers a session will use without making a model request.",
      "metadata": {
        "internal": true
      },
      "name": "harness::system-prompt::get",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "SelectedSystemPrompt": {
            "properties": {
              "body": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "strategy": {
                "allOf": [
                  {
                    "$ref": "#/definitions/SystemPromptStrategy"
                  }
                ],
                "default": "enrich"
              }
            },
            "required": [
              "body",
              "name"
            ],
            "type": "object"
          },
          "SystemPromptStrategy": {
            "description": "How a caller-supplied system prompt combines with the built-in identity prompt.",
            "oneOf": [
              {
                "description": "Caller prompt replaces the built-in prompt verbatim.",
                "enum": [
                  "override"
                ],
                "type": "string"
              },
              {
                "description": "Caller prompt is appended to the built-in identity prompt.",
                "enum": [
                  "enrich"
                ],
                "type": "string"
              },
              {
                "description": "No system prompt is sent to the model.",
                "enum": [
                  "disabled"
                ],
                "type": "string"
              }
            ]
          }
        },
        "properties": {
          "default_only": {
            "default": false,
            "description": "Return only the built-in default layer, without session, runtime, registry, or hook layers.",
            "type": "boolean"
          },
          "filesystem_root": {
            "type": [
              "string",
              "null"
            ]
          },
          "selected_prompt": {
            "anyOf": [
              {
                "$ref": "#/definitions/SelectedSystemPrompt"
              },
              {
                "type": "null"
              }
            ]
          },
          "session_id": {
            "type": "string"
          }
        },
        "required": [
          "session_id"
        ],
        "title": "SystemPromptRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "SystemPromptPart": {
            "properties": {
              "body": {
                "type": "string"
              },
              "kind": {
                "$ref": "#/definitions/SystemPromptPartKind"
              },
              "name": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "body",
              "kind"
            ],
            "type": "object"
          },
          "SystemPromptPartKind": {
            "enum": [
              "built_in",
              "selected",
              "skills",
              "runtime",
              "injected"
            ],
            "type": "string"
          }
        },
        "properties": {
          "parts": {
            "items": {
              "$ref": "#/definitions/SystemPromptPart"
            },
            "type": "array"
          }
        },
        "required": [
          "parts"
        ],
        "title": "SystemPromptPreview",
        "type": "object"
      }
    },
    {
      "description": "Internal control-plane: remove trigger bindings owned by a root harness session tree.",
      "metadata": {
        "internal": true
      },
      "name": "harness::teardown",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "root_session_id": {
            "type": "string"
          }
        },
        "required": [
          "root_session_id"
        ],
        "title": "TeardownRequestV1",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "properties": {
          "removed": {
            "format": "uint64",
            "minimum": 0,
            "type": "integer"
          }
        },
        "required": [
          "removed"
        ],
        "title": "TeardownResponseV1",
        "type": "object"
      }
    },
    {
      "description": "Internal fire handler for a harness-registered trigger binding: evaluates the binding's conditions, projects the event into the target's payload, and dispatches it (a wake into the owner session, or a plain function call). Never called directly — register bindings with engine::register_trigger.",
      "metadata": {
        "internal": true
      },
      "name": "harness::trigger::deliver",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "description": "Arbitrary fired-event payload from the subscribed trigger.",
        "title": "DeliverEvent",
        "type": [
          "null",
          "boolean",
          "number",
          "string",
          "array",
          "object"
        ]
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "delivered": {
            "description": "Whether the target was dispatched this fire.",
            "type": "boolean"
          },
          "gate": {
            "description": "Which gate or condition stopped it. Present iff `!delivered`.",
            "type": [
              "string",
              "null"
            ]
          },
          "note": {
            "description": "Why. Present iff `!delivered`.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "delivered"
        ],
        "title": "DeliverResult",
        "type": "object"
      }
    },
    {
      "description": "List the trigger bindings a session owns: subscription id, trigger type/config, target (absent = notifies the owner), label, conditions, lifecycle, and fire count. In-turn calls may omit `session_id`.",
      "metadata": {},
      "name": "harness::triggers::list",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "session_id": {
            "default": null,
            "description": "Owner session whose bindings to list; in-turn calls may omit it (the calling session is injected).",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "title": "TriggersListRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "ConditionSpec": {
            "description": "One declared condition. Evaluated at fire time with the typed decision contract; ordinary iii functions, so a barrier or a claim is just a function someone wrote.",
            "properties": {
              "config": true,
              "function_id": {
                "type": "string"
              }
            },
            "required": [
              "function_id"
            ],
            "type": "object"
          },
          "TriggerRow": {
            "description": "One binding, as data. `trigger_type`/`config` are read from the canonicalised registration request and absent on records that predate it.",
            "properties": {
              "action": {
                "description": "Human-readable event text declared as `metadata.action`.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "conditions": {
                "items": {
                  "$ref": "#/definitions/ConditionSpec"
                },
                "type": "array"
              },
              "config": true,
              "created_at": {
                "format": "int64",
                "type": "integer"
              },
              "expires_at": {
                "format": "int64",
                "type": [
                  "integer",
                  "null"
                ]
              },
              "fires": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "label": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "max_fires": {
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "once": {
                "type": "boolean"
              },
              "subscription_id": {
                "type": "string"
              },
              "target": {
                "description": "The function a fire calls. Absent for a wake — the fire notifies the owner session.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "trigger_id": {
                "description": "The engine's own trigger id (absent only in the brief window before the engine acknowledged the registration).",
                "type": [
                  "string",
                  "null"
                ]
              },
              "trigger_type": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "created_at",
              "fires",
              "once",
              "subscription_id"
            ],
            "type": "object"
          }
        },
        "properties": {
          "subscriptions": {
            "items": {
              "$ref": "#/definitions/TriggerRow"
            },
            "type": "array"
          }
        },
        "required": [
          "subscriptions"
        ],
        "title": "TriggersListResponse",
        "type": "object"
      }
    },
    {
      "description": "Tear down one trigger binding by subscription id (engine trigger and durable record); a still-armed wake notifies its parked owner. `session_id` must name the owner; in-turn calls may omit it.",
      "metadata": {},
      "name": "harness::triggers::unregister",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "session_id": {
            "default": null,
            "description": "The binding's owner session; in-turn calls may omit it (the calling session is injected).",
            "type": [
              "string",
              "null"
            ]
          },
          "subscription_id": {
            "description": "The subscription to remove (`id` is accepted as an alias).",
            "type": "string"
          }
        },
        "required": [
          "subscription_id"
        ],
        "title": "TriggersUnregisterRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "removed": {
            "description": "False when no record existed (already retired) — honest, not an error.",
            "type": "boolean"
          }
        },
        "required": [
          "removed"
        ],
        "title": "TriggersUnregisterResponse",
        "type": "object"
      }
    },
    {
      "description": "Internal durable loop step (enqueued onto the harness-turn queue); not called directly.",
      "metadata": {
        "internal": true,
        "trace_hidden": true
      },
      "name": "harness::turn",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "description": "The enqueued `harness::turn` step payload.",
        "properties": {
          "depth": {
            "default": 0,
            "description": "Sub-agent depth carried from the turn record (0 = top-level).",
            "format": "uint32",
            "minimum": 0,
            "type": "integer"
          },
          "message_preview": {
            "description": "Preview carried from the turn record so the step can stamp the `iii.tag.message` baggage before any state read.",
            "type": [
              "string",
              "null"
            ]
          },
          "session_id": {
            "type": "string"
          },
          "step": {
            "format": "uint64",
            "minimum": 0,
            "type": "integer"
          },
          "turn_id": {
            "type": "string"
          }
        },
        "required": [
          "session_id",
          "step",
          "turn_id"
        ],
        "title": "TurnStepPayload",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "TurnStatus": {
            "description": "The coarse, harness-internal turn lifecycle (harness.md § API Reference). Finer-grained than the session's `status`, which the loop derives from it.",
            "enum": [
              "running",
              "awaiting_functions",
              "completed",
              "cancelled",
              "failed"
            ],
            "type": "string"
          }
        },
        "properties": {
          "next_step": {
            "format": "uint64",
            "minimum": 0,
            "type": [
              "integer",
              "null"
            ]
          },
          "session_id": {
            "type": "string"
          },
          "skipped": {
            "default": false,
            "description": "True when a redelivered/stale step was acked and dropped.",
            "type": "boolean"
          },
          "status": {
            "$ref": "#/definitions/TurnStatus"
          }
        },
        "required": [
          "session_id",
          "status"
        ],
        "title": "TurnStepResult",
        "type": "object"
      }
    },
    {
      "description": "Serve the harness worker's injected console UI assets (content function for its console:script / console:style triggers).",
      "metadata": {
        "internal": true
      },
      "name": "harness::ui-content",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "description": "Input of the content function: the console asks for one asset by path.",
        "properties": {
          "path": {
            "description": "The asset path from the trigger config (e.g. `state/page.js`).",
            "type": "string"
          }
        },
        "required": [
          "path"
        ],
        "title": "UiContentInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "description": "Output of the content function.",
        "properties": {
          "content": {
            "description": "The asset source, verbatim.",
            "type": "string"
          },
          "content_type": {
            "description": "MIME type the console should serve the asset with.",
            "type": "string"
          }
        },
        "required": [
          "content",
          "content_type"
        ],
        "title": "UiContentResult",
        "type": "object"
      }
    },
    {
      "description": "Internal control-plane: remove a still-parked queued message by entry_id (the console's edit-queued path).",
      "metadata": {
        "internal": true
      },
      "name": "harness::unqueue",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "entry_id": {
            "description": "The queued row's transcript entry id, as surfaced by `harness::status` → `queued[].entry_id`. Stable and client-visible (the internal row id is not), so removals target it.",
            "type": "string"
          },
          "session_id": {
            "type": "string"
          }
        },
        "required": [
          "entry_id",
          "session_id"
        ],
        "title": "UnqueueRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "removed": {
            "description": "False when no still-parked row matched — already drained or unknown.",
            "type": "boolean"
          }
        },
        "required": [
          "removed"
        ],
        "title": "UnqueueResponse",
        "type": "object"
      }
    }
  ],
  "triggers": [
    {
      "description": "Synchronous hook: after the final assistant message update. Observe only.",
      "invocation_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "description": "The `config` of a `harness::hook::<point>` trigger binding.",
        "properties": {
          "functions": {
            "description": "pre/post_trigger only: target function_id globs to consult on.",
            "items": {
              "type": "string"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "on_error": {
            "description": "Failure policy (default fail_closed for pre_* and post_turn, fail_open for the other post_*).",
            "type": [
              "string",
              "null"
            ]
          },
          "payload": {
            "description": "post_turn only: template mode — send THIS argument object to the bound function instead of the hook envelope, with the turn's parsed result injected at `result_into`. Lets a plain composition function (`fp::pipe`) validate turns without speaking the hook contract; its receipt is read as the verdict (`valid`, or `short_circuited`)."
          },
          "priority": {
            "description": "Chain order: ascending, ties broken by function_id (default 0).",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "result_into": {
            "description": "post_turn template mode: JSON pointer where the result lands in `payload` (default `/value`).",
            "type": [
              "string",
              "null"
            ]
          },
          "retry_prompt": {
            "description": "post_turn only: custom corrective prompt sent VERBATIM when this validator denies (replaces the generic \"result was not accepted\" wrapper). Placeholders: `{value}` = the validator's measured value (fp::pipe receipt `value_preview`), `{reason}` = the deny reason. Validator ERRORS keep the generic text — a task-shaped prompt must not mask a broken validator.",
            "type": [
              "string",
              "null"
            ]
          },
          "sessions": {
            "description": "pre_turn/post_turn: session_id globs this hook applies to (omit = all).",
            "items": {
              "type": "string"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "timeout_ms": {
            "description": "Per-invocation timeout (default 5000ms).",
            "format": "uint64",
            "minimum": 0,
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "title": "HookTriggerConfig",
        "type": "object"
      },
      "metadata": {},
      "name": "harness::hook::post-generate",
      "return_schema": {}
    },
    {
      "description": "Synchronous hook: after the target returns, before the result is appended. May rewrite content/details/is_error.",
      "invocation_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "description": "The `config` of a `harness::hook::<point>` trigger binding.",
        "properties": {
          "functions": {
            "description": "pre/post_trigger only: target function_id globs to consult on.",
            "items": {
              "type": "string"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "on_error": {
            "description": "Failure policy (default fail_closed for pre_* and post_turn, fail_open for the other post_*).",
            "type": [
              "string",
              "null"
            ]
          },
          "payload": {
            "description": "post_turn only: template mode — send THIS argument object to the bound function instead of the hook envelope, with the turn's parsed result injected at `result_into`. Lets a plain composition function (`fp::pipe`) validate turns without speaking the hook contract; its receipt is read as the verdict (`valid`, or `short_circuited`)."
          },
          "priority": {
            "description": "Chain order: ascending, ties broken by function_id (default 0).",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "result_into": {
            "description": "post_turn template mode: JSON pointer where the result lands in `payload` (default `/value`).",
            "type": [
              "string",
              "null"
            ]
          },
          "retry_prompt": {
            "description": "post_turn only: custom corrective prompt sent VERBATIM when this validator denies (replaces the generic \"result was not accepted\" wrapper). Placeholders: `{value}` = the validator's measured value (fp::pipe receipt `value_preview`), `{reason}` = the deny reason. Validator ERRORS keep the generic text — a task-shaped prompt must not mask a broken validator.",
            "type": [
              "string",
              "null"
            ]
          },
          "sessions": {
            "description": "pre_turn/post_turn: session_id globs this hook applies to (omit = all).",
            "items": {
              "type": "string"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "timeout_ms": {
            "description": "Per-invocation timeout (default 5000ms).",
            "format": "uint64",
            "minimum": 0,
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "title": "HookTriggerConfig",
        "type": "object"
      },
      "metadata": {},
      "name": "harness::hook::post-trigger",
      "return_schema": {}
    },
    {
      "description": "Synchronous hook: at finalize, after the output contract validated the result, before the turn completes. Deny re-prompts the turn (bounded by max_validation_retries). Config `sessions` globs scope it; config `payload`+`result_into` bind a plain composition function (fp::pipe) as the validator.",
      "invocation_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "description": "The `config` of a `harness::hook::<point>` trigger binding.",
        "properties": {
          "functions": {
            "description": "pre/post_trigger only: target function_id globs to consult on.",
            "items": {
              "type": "string"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "on_error": {
            "description": "Failure policy (default fail_closed for pre_* and post_turn, fail_open for the other post_*).",
            "type": [
              "string",
              "null"
            ]
          },
          "payload": {
            "description": "post_turn only: template mode — send THIS argument object to the bound function instead of the hook envelope, with the turn's parsed result injected at `result_into`. Lets a plain composition function (`fp::pipe`) validate turns without speaking the hook contract; its receipt is read as the verdict (`valid`, or `short_circuited`)."
          },
          "priority": {
            "description": "Chain order: ascending, ties broken by function_id (default 0).",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "result_into": {
            "description": "post_turn template mode: JSON pointer where the result lands in `payload` (default `/value`).",
            "type": [
              "string",
              "null"
            ]
          },
          "retry_prompt": {
            "description": "post_turn only: custom corrective prompt sent VERBATIM when this validator denies (replaces the generic \"result was not accepted\" wrapper). Placeholders: `{value}` = the validator's measured value (fp::pipe receipt `value_preview`), `{reason}` = the deny reason. Validator ERRORS keep the generic text — a task-shaped prompt must not mask a broken validator.",
            "type": [
              "string",
              "null"
            ]
          },
          "sessions": {
            "description": "pre_turn/post_turn: session_id globs this hook applies to (omit = all).",
            "items": {
              "type": "string"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "timeout_ms": {
            "description": "Per-invocation timeout (default 5000ms).",
            "format": "uint64",
            "minimum": 0,
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "title": "HookTriggerConfig",
        "type": "object"
      },
      "metadata": {},
      "name": "harness::hook::post-turn",
      "return_schema": {}
    },
    {
      "description": "Synchronous hook: after context assembly, before generation. May extend the system prompt, append messages, or veto. Static-only bindings may declare their exact contribution as metadata.inject_prompt.",
      "invocation_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "description": "The `config` of a `harness::hook::<point>` trigger binding.",
        "properties": {
          "functions": {
            "description": "pre/post_trigger only: target function_id globs to consult on.",
            "items": {
              "type": "string"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "on_error": {
            "description": "Failure policy (default fail_closed for pre_* and post_turn, fail_open for the other post_*).",
            "type": [
              "string",
              "null"
            ]
          },
          "payload": {
            "description": "post_turn only: template mode — send THIS argument object to the bound function instead of the hook envelope, with the turn's parsed result injected at `result_into`. Lets a plain composition function (`fp::pipe`) validate turns without speaking the hook contract; its receipt is read as the verdict (`valid`, or `short_circuited`)."
          },
          "priority": {
            "description": "Chain order: ascending, ties broken by function_id (default 0).",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "result_into": {
            "description": "post_turn template mode: JSON pointer where the result lands in `payload` (default `/value`).",
            "type": [
              "string",
              "null"
            ]
          },
          "retry_prompt": {
            "description": "post_turn only: custom corrective prompt sent VERBATIM when this validator denies (replaces the generic \"result was not accepted\" wrapper). Placeholders: `{value}` = the validator's measured value (fp::pipe receipt `value_preview`), `{reason}` = the deny reason. Validator ERRORS keep the generic text — a task-shaped prompt must not mask a broken validator.",
            "type": [
              "string",
              "null"
            ]
          },
          "sessions": {
            "description": "pre_turn/post_turn: session_id globs this hook applies to (omit = all).",
            "items": {
              "type": "string"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "timeout_ms": {
            "description": "Per-invocation timeout (default 5000ms).",
            "format": "uint64",
            "minimum": 0,
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "title": "HookTriggerConfig",
        "type": "object"
      },
      "metadata": {},
      "name": "harness::hook::pre-generate",
      "return_schema": {}
    },
    {
      "description": "Synchronous hook: after the allow/deny policy passes, before the target is invoked. May deny, hold, or rewrite arguments.",
      "invocation_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "description": "The `config` of a `harness::hook::<point>` trigger binding.",
        "properties": {
          "functions": {
            "description": "pre/post_trigger only: target function_id globs to consult on.",
            "items": {
              "type": "string"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "on_error": {
            "description": "Failure policy (default fail_closed for pre_* and post_turn, fail_open for the other post_*).",
            "type": [
              "string",
              "null"
            ]
          },
          "payload": {
            "description": "post_turn only: template mode — send THIS argument object to the bound function instead of the hook envelope, with the turn's parsed result injected at `result_into`. Lets a plain composition function (`fp::pipe`) validate turns without speaking the hook contract; its receipt is read as the verdict (`valid`, or `short_circuited`)."
          },
          "priority": {
            "description": "Chain order: ascending, ties broken by function_id (default 0).",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "result_into": {
            "description": "post_turn template mode: JSON pointer where the result lands in `payload` (default `/value`).",
            "type": [
              "string",
              "null"
            ]
          },
          "retry_prompt": {
            "description": "post_turn only: custom corrective prompt sent VERBATIM when this validator denies (replaces the generic \"result was not accepted\" wrapper). Placeholders: `{value}` = the validator's measured value (fp::pipe receipt `value_preview`), `{reason}` = the deny reason. Validator ERRORS keep the generic text — a task-shaped prompt must not mask a broken validator.",
            "type": [
              "string",
              "null"
            ]
          },
          "sessions": {
            "description": "pre_turn/post_turn: session_id globs this hook applies to (omit = all).",
            "items": {
              "type": "string"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "timeout_ms": {
            "description": "Per-invocation timeout (default 5000ms).",
            "format": "uint64",
            "minimum": 0,
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "title": "HookTriggerConfig",
        "type": "object"
      },
      "metadata": {},
      "name": "harness::hook::pre-trigger",
      "return_schema": {}
    },
    {
      "description": "Synchronous hook: first step of a turn, before any model spend. May veto.",
      "invocation_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "description": "The `config` of a `harness::hook::<point>` trigger binding.",
        "properties": {
          "functions": {
            "description": "pre/post_trigger only: target function_id globs to consult on.",
            "items": {
              "type": "string"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "on_error": {
            "description": "Failure policy (default fail_closed for pre_* and post_turn, fail_open for the other post_*).",
            "type": [
              "string",
              "null"
            ]
          },
          "payload": {
            "description": "post_turn only: template mode — send THIS argument object to the bound function instead of the hook envelope, with the turn's parsed result injected at `result_into`. Lets a plain composition function (`fp::pipe`) validate turns without speaking the hook contract; its receipt is read as the verdict (`valid`, or `short_circuited`)."
          },
          "priority": {
            "description": "Chain order: ascending, ties broken by function_id (default 0).",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "result_into": {
            "description": "post_turn template mode: JSON pointer where the result lands in `payload` (default `/value`).",
            "type": [
              "string",
              "null"
            ]
          },
          "retry_prompt": {
            "description": "post_turn only: custom corrective prompt sent VERBATIM when this validator denies (replaces the generic \"result was not accepted\" wrapper). Placeholders: `{value}` = the validator's measured value (fp::pipe receipt `value_preview`), `{reason}` = the deny reason. Validator ERRORS keep the generic text — a task-shaped prompt must not mask a broken validator.",
            "type": [
              "string",
              "null"
            ]
          },
          "sessions": {
            "description": "pre_turn/post_turn: session_id globs this hook applies to (omit = all).",
            "items": {
              "type": "string"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "timeout_ms": {
            "description": "Per-invocation timeout (default 5000ms).",
            "format": "uint64",
            "minimum": 0,
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "title": "HookTriggerConfig",
        "type": "object"
      },
      "metadata": {},
      "name": "harness::hook::pre-turn",
      "return_schema": {}
    },
    {
      "description": "A message parked in a session's server-side queue while its turn streams.",
      "invocation_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "description": "Binding config shared by both turn-event types.",
        "properties": {
          "parent_session_id": {
            "description": "Only deliver sub-agent events whose parent is this session.",
            "type": [
              "string",
              "null"
            ]
          },
          "session_id": {
            "description": "Only deliver events for this session.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "title": "TurnEventBindingConfig",
        "type": "object"
      },
      "metadata": {},
      "name": "harness::message-queued",
      "return_schema": {}
    },
    {
      "description": "The harness completed boot and can accept turns.",
      "invocation_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "title": "ReadyBindingConfig",
        "type": "object"
      },
      "metadata": {},
      "name": "harness::ready",
      "return_schema": {}
    },
    {
      "description": "A session's trigger-binding set or fire count changed — refetch harness::triggers::list.",
      "invocation_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "description": "Binding config shared by both turn-event types.",
        "properties": {
          "parent_session_id": {
            "description": "Only deliver sub-agent events whose parent is this session.",
            "type": [
              "string",
              "null"
            ]
          },
          "session_id": {
            "description": "Only deliver events for this session.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "title": "TurnEventBindingConfig",
        "type": "object"
      },
      "metadata": {},
      "name": "harness::triggers-changed",
      "return_schema": {}
    },
    {
      "description": "A harness turn reached a terminal status (completed/cancelled/failed).",
      "invocation_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "description": "Binding config shared by both turn-event types.",
        "properties": {
          "parent_session_id": {
            "description": "Only deliver sub-agent events whose parent is this session.",
            "type": [
              "string",
              "null"
            ]
          },
          "session_id": {
            "description": "Only deliver events for this session.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "title": "TurnEventBindingConfig",
        "type": "object"
      },
      "metadata": {},
      "name": "harness::turn-completed",
      "return_schema": {}
    },
    {
      "description": "A harness turn began executing (first loop step).",
      "invocation_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "description": "Binding config shared by both turn-event types.",
        "properties": {
          "parent_session_id": {
            "description": "Only deliver sub-agent events whose parent is this session.",
            "type": [
              "string",
              "null"
            ]
          },
          "session_id": {
            "description": "Only deliver events for this session.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "title": "TurnEventBindingConfig",
        "type": "object"
      },
      "metadata": {},
      "name": "harness::turn-started",
      "return_schema": {}
    },
    {
      "description": "One-shot deadline: fires exactly once at `at` (epoch ms). Register with { \"in_ms\": <relative ms> } — resolved to an absolute `at` at registration — or { \"at\": <epoch ms> }. The natural second leg of any armed wake or fan-in gate: 'wake me when X happens, or tell me at T that it did not'. Fires once and retires; for recurrence use `cron`.",
      "invocation_schema": {},
      "metadata": {},
      "name": "timer",
      "return_schema": {}
    }
  ]
}
```
