skip to content
$worker

harness

v1.8.25

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

iiiverified
1,703 installs0 in 7d0 today
install
$iii trigger compose::add worker=harness@1.8.25
binarylicense: Apache-2.0agentautonomousharnessloop
  • macOS: arm64
  • Linux: arm64 · armv7 · x64
  • Windows: arm64 · x64

exact versions are immutable; binary and bundle artifacts are digest-pinned.

agent-ready brief for v1.8.25
install + config + dependencies + readme + api reference, all in one place. fetch as agent-context.md for an llm to consume.
the same content rendered as discrete blocks below is exposed as a single markdown document at /workers/harness.md?version=1.8.25. paste it into an llm prompt or pipe it through curl from a worker.

install

install
$iii trigger compose::add worker=harness@1.8.25

dependencies

readme

README.md

harness

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

Install: iii trigger compose::add worker=harness License: Apache 2.0 Built with Rust harness on the workers registry ade on the workers registry

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 (transcript), context-manager (token budgeting, soft dependency), and 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:

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
# New terminal, same folder. `compose::add` updates this Compose project.
cd iii-app
iii trigger compose::add worker=harness worker=ade
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. Automatic generation recovery requires partial output from the failed response. A startup failure with no output ends the turn with a durable failure notice; it does not consume the partial-response recovery budget.

Harness turn waterfall in the iii console

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 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: the functions to trigger, the triggers to bind, and the canonical consumer patterns.

Local development

See 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: "::", description: "", 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: "" }
  • directory::registry::workers::info { name } to judge fit
  • choose an operation id and register a one-shot compose-operation wake with { "operation_id": "", "terminal_only": true }
  • call compose::add { worker: "", 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::" }. 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.

Adding workers with container settings

Fetch compose::schema { function_id: "compose::add" } before choosing the payload. Use container objects only if the running daemon's schema supports them. The singular worker field remains a string shorthand. For settings, use workers, which can mix strings and objects. Put settings inside each object, not at the request's top level. Only add accepts objects; update and remove take worker names.

After registering the one-shot wake described above, call compose::add with a payload like this (the local worker directory and env file must already exist):

{
  "operation_id": "<operation-id>",
  "workers": [
    "state",
    {
      "worker": "./workers/api",
      "start_after": ["state"],
      "scripts": {
        "pre_run": "pnpm build",
        "pre_run_timeout": "60s",
        "run": "pnpm start",
        "post_run": "echo stopped"
      },
      "config_name": "api",
      "config_override": { "port": 3000 },
      "working_dir": "./workers/api",
      "environment": { "NODE_ENV": "development" },
      "env_file": ["./api.env"],
      "startup_timeout": "30s"
    }
  ]
}

worker accepts a package name, name@version, registry reference, or local directory, including package:// and path:// sources. Objects also accept version for packages; it must agree with any version in worker. Omission resolves the latest matching package version, so keep an explicit version when it must stay pinned.

Use scripts (plural); scripts.run is valid only for local workers. start_after contains container keys, derived from the last part of each worker name or directory; required package dependencies are also included. config_name selects the base configuration, and config_override supplies values over it. environment values must be strings. startup_timeout limits the wait for registration.

Relative worker, working_dir, and env_file paths start at the compose file's directory. working_dir sets the process and hook directory; when omitted, local workers use their own directory and packages use the compose directory.

For an existing container, omitted settings stay in place. A supplied field replaces that whole field, including scripts, environment, and config_override; these are not partial map edits. Use {} or [] to clear maps or lists. A supplied start_after replaces the list while retaining required package dependencies. Changes can restart running workers. The acceptance response does not mean ready: finish the same compose-operation workflow before using the worker.

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:

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: ~/.iii/data/harness/projects.json  # durable operator project catalog (default: data/harness-projects.json under III_COMPOSE_DIR / cwd)
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.

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): 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 (/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. 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 — 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.

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 skills are PRELOADED: each id's body is fetched once from directory::skills::get and frozen into a block of sections appended to the prompt (ids the directory cannot serve are named as unavailable), so the skill is in context on the first step; the session's skills index is never narrowed by a profile — only an explicit options.skills does that. 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). When the profile declares (or inherits) functions — its PRELOADED functions, engine function ids it uses routinely — the harness renders each one's current description and compacted request schema into a block appended to the frozen prompt (contracts come from the cached registry snapshot, with one engine::functions::info batch for ids the snapshot cannot vouch for; ids the engine does not know are named as unavailable), so the model calls them on the first step instead of spending a search and a contract lookup per session. The block comes first, after it. The frozen name/icon/color/model/effort/skills/functions 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 (preloaded functions and skills included) is the child's whole identity, its 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. A spawn that names NO profile continues the parent turn's: an agent running under a profile fans work out to itself, not to a stranger wearing the built-in identity, and the child re-resolves that same id so its own preloaded functions and skills arrive with it. options.system_prompt — the escape hatch for a child that genuinely needs a different identity — sheds the inherited profile instead of colliding with it, and a parentless spawn (console, workflow, CLI) has no parent turn to inherit from. 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.

The harness ships one profile of its own, worker-builder (agents/worker-builder.md): an identity that extends the bundled iii base and takes a new worker for this repository from scope to scaffold, CI gates, live verification on the bus, pull request, and an experimental registry release, asking before every irreversible step. It is published in the harness skills payload as agents/worker-builder.md, which directory::skills::download { worker: "harness" } routes into the directory's agents_folder; copying the file there by hand works the same. Its skills preload the six knowledge skills from iii-hq/iii/skills (npx skills add iii-hq/iii/skills) into every session's prompt; missing ones are named as unavailable, not failures. Then harness::send { options: { agent: "worker-builder" } } (or the console's agent picker) runs it.

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 when the model calls that function — or up front, as sections, when an agent profile preloads them. 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). Payload: session_id, turn_id, timestamp, depth (0 = top level), message_preview (first characters of the message that started the turn, when there is one), and parent / parent_session_id for sub-agents. 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: boolfalse 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 for the hook contract and chain semantics.

api reference (json)

agent-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": {
                  "attachment_id": {
                    "description": "Optional link to the stored original of this inline image (`session::put-attachment`, resolvable with `session::get-attachment`). Lets readers ask `session::messages { include_image_data: false }` and fetch the bytes lazily instead of receiving them inline. Persisted verbatim on the transcript; model-bound consumers never see it (see [`ContentBlock::strip_files`]). Omitted on the wire when absent so legacy transcripts stay byte-identical.",
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "data": {
                    "type": "string"
                  },
                  "mime": {
                    "type": "string"
                  },
                  "type": {
                    "enum": [
                      "image"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "data",
                  "mime",
                  "type"
                ],
                "type": "object"
              },
              {
                "description": "Reference to an original upload in the session-manager attachment store (resolvable with `session::get-attachment`). A REFERENCE ONLY: the bytes are never inline. Persisted verbatim on user messages and stripped from every model-bound copy (see [`ContentBlock::strip_files`]).",
                "properties": {
                  "attachment_id": {
                    "type": "string"
                  },
                  "mime": {
                    "type": "string"
                  },
                  "name": {
                    "type": "string"
                  },
                  "size": {
                    "format": "uint64",
                    "minimum": 0,
                    "type": "integer"
                  },
                  "type": {
                    "enum": [
                      "file"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "attachment_id",
                  "mime",
                  "name",
                  "size",
                  "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": {
                  "attachment_id": {
                    "description": "Optional link to the stored original of this inline image (`session::put-attachment`, resolvable with `session::get-attachment`). Lets readers ask `session::messages { include_image_data: false }` and fetch the bytes lazily instead of receiving them inline. Persisted verbatim on the transcript; model-bound consumers never see it (see [`ContentBlock::strip_files`]). Omitted on the wire when absent so legacy transcripts stay byte-identical.",
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "data": {
                    "type": "string"
                  },
                  "mime": {
                    "type": "string"
                  },
                  "type": {
                    "enum": [
                      "image"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "data",
                  "mime",
                  "type"
                ],
                "type": "object"
              },
              {
                "description": "Reference to an original upload in the session-manager attachment store (resolvable with `session::get-attachment`). A REFERENCE ONLY: the bytes are never inline. Persisted verbatim on user messages and stripped from every model-bound copy (see [`ContentBlock::strip_files`]).",
                "properties": {
                  "attachment_id": {
                    "type": "string"
                  },
                  "mime": {
                    "type": "string"
                  },
                  "name": {
                    "type": "string"
                  },
                  "size": {
                    "format": "uint64",
                    "minimum": 0,
                    "type": "integer"
                  },
                  "type": {
                    "enum": [
                      "file"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "attachment_id",
                  "mime",
                  "name",
                  "size",
                  "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 for the session tree `root_session_id` belongs to (`session_id` is accepted as an alias, and a sub-agent id is resolved to its root). `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#",
        "oneOf": [
          {
            "required": [
              "root_session_id"
            ]
          },
          {
            "required": [
              "session_id"
            ]
          }
        ],
        "properties": {
          "root_session_id": {
            "description": "Any session in the tree. `session_id` is accepted as an alias, and a child id is walked up to its root, so the id that addresses `harness::status` addresses the tree here too.",
            "type": "string"
          },
          "session_id": {
            "description": "Any session in the tree. `session_id` is accepted as an alias, and a child id is walked up to its root, so the id that addresses `harness::status` addresses the tree here too.",
            "type": "string"
          }
        },
        "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": {
                "description": "Summed over every generation that reported it. `null` means at least one generation did not report the counter (a provider that omits it, or a turn that failed before usage came back) — never a measured zero, so the key is always present and a reader can tell the two apart.",
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "cache_write_tokens": {
                "description": "Summed over every generation that reported it. `null` means at least one generation did not report the counter (a provider that omits it, or a turn that failed before usage came back) — never a measured zero, so the key is always present and a reader can tell the two apart.",
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "cost_usd": {
                "description": "Summed over every generation that reported it. `null` means at least one generation did not report the counter (a provider that omits it, or a turn that failed before usage came back) — never a measured zero, so the key is always present and a reader can tell the two apart.",
                "format": "double",
                "type": [
                  "number",
                  "null"
                ]
              },
              "function_call_errors": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "function_calls": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "input_tokens": {
                "description": "Summed over every generation that reported it. `null` means at least one generation did not report the counter (a provider that omits it, or a turn that failed before usage came back) — never a measured zero, so the key is always present and a reader can tell the two apart.",
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "output_tokens": {
                "description": "Summed over every generation that reported it. `null` means at least one generation did not report the counter (a provider that omits it, or a turn that failed before usage came back) — never a measured zero, so the key is always present and a reader can tell the two apart.",
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "reasoning_tokens": {
                "description": "Summed over every generation that reported it. `null` means at least one generation did not report the counter (a provider that omits it, or a turn that failed before usage came back) — never a measured zero, so the key is always present and a reader can tell the two apart.",
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "sessions": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "turns": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              }
            },
            "required": [
              "cache_read_tokens",
              "cache_write_tokens",
              "cost_usd",
              "function_call_errors",
              "function_calls",
              "input_tokens",
              "output_tokens",
              "reasoning_tokens",
              "sessions",
              "turns"
            ],
            "type": "object"
          },
          "SessionUsageV1": {
            "additionalProperties": false,
            "properties": {
              "cache_read_tokens": {
                "description": "Summed over every generation that reported it. `null` means at least one generation did not report the counter (a provider that omits it, or a turn that failed before usage came back) — never a measured zero, so the key is always present and a reader can tell the two apart.",
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "cache_write_tokens": {
                "description": "Summed over every generation that reported it. `null` means at least one generation did not report the counter (a provider that omits it, or a turn that failed before usage came back) — never a measured zero, so the key is always present and a reader can tell the two apart.",
                "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": {
                "description": "Summed over every generation that reported it. `null` means at least one generation did not report the counter (a provider that omits it, or a turn that failed before usage came back) — never a measured zero, so the key is always present and a reader can tell the two apart.",
                "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": {
                "description": "Summed over every generation that reported it. `null` means at least one generation did not report the counter (a provider that omits it, or a turn that failed before usage came back) — never a measured zero, so the key is always present and a reader can tell the two apart.",
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "output_tokens": {
                "description": "Summed over every generation that reported it. `null` means at least one generation did not report the counter (a provider that omits it, or a turn that failed before usage came back) — never a measured zero, so the key is always present and a reader can tell the two apart.",
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "parent_session_id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "reasoning_tokens": {
                "description": "Summed over every generation that reported it. `null` means at least one generation did not report the counter (a provider that omits it, or a turn that failed before usage came back) — never a measured zero, so the key is always present and a reader can tell the two apart.",
                "format": "uint64",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "session_id": {
                "type": "string"
              },
              "turns": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              }
            },
            "required": [
              "cache_read_tokens",
              "cache_write_tokens",
              "cost_usd",
              "depth",
              "function_call_errors",
              "function_calls",
              "input_tokens",
              "output_tokens",
              "reasoning_tokens",
              "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. Check `harness::status` for child health; 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": {
            "description": "Closed palette consumed by UIs. A colour outside it (models like to say `orange`) falls back to `neutral` instead of failing the whole spawn on a display-only field — a rejected spawn cost a live orchestrator a step and a re-dispatch (MOT-4718).",
            "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`. Omitted, an in-turn spawn continues the parent turn's profile (name `options.system_prompt` for a child that needs a different identity).",
            "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 a session's current turn. Returns a lean summary by default; pass verbose: true for the full runtime report and untruncated result.",
      "metadata": {},
      "name": "harness::status",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "session_id": {
            "type": "string"
          },
          "verbose": {
            "default": false,
            "description": "Include the full runtime report and unmodified result.",
            "type": "boolean"
          }
        },
        "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": {
                  "attachment_id": {
                    "description": "Optional link to the stored original of this inline image (`session::put-attachment`, resolvable with `session::get-attachment`). Lets readers ask `session::messages { include_image_data: false }` and fetch the bytes lazily instead of receiving them inline. Persisted verbatim on the transcript; model-bound consumers never see it (see [`ContentBlock::strip_files`]). Omitted on the wire when absent so legacy transcripts stay byte-identical.",
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "data": {
                    "type": "string"
                  },
                  "mime": {
                    "type": "string"
                  },
                  "type": {
                    "enum": [
                      "image"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "data",
                  "mime",
                  "type"
                ],
                "type": "object"
              },
              {
                "description": "Reference to an original upload in the session-manager attachment store (resolvable with `session::get-attachment`). A REFERENCE ONLY: the bytes are never inline. Persisted verbatim on user messages and stripped from every model-bound copy (see [`ContentBlock::strip_files`]).",
                "properties": {
                  "attachment_id": {
                    "type": "string"
                  },
                  "mime": {
                    "type": "string"
                  },
                  "name": {
                    "type": "string"
                  },
                  "size": {
                    "format": "uint64",
                    "minimum": 0,
                    "type": "integer"
                  },
                  "type": {
                    "enum": [
                      "file"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "attachment_id",
                  "mime",
                  "name",
                  "size",
                  "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"
              }
            ]
          },
          "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"
          },
          "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"
          },
          "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"
          },
          "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",
                  "null"
                ]
              },
              "children": {
                "items": {
                  "$ref": "#/definitions/ChildRef"
                },
                "type": "array"
              },
              "context": {
                "anyOf": [
                  {
                    "$ref": "#/definitions/ContextSnapshotV1"
                  },
                  {
                    "type": "null"
                  }
                ],
                "default": null,
                "description": "The last generate step's context accounting (budget, categories, provider-exact usage once it lands) — what a UI meter should show instead of re-estimating the transcript. Verbose only; absent before the first generate."
              },
              "depth": {
                "format": "uint32",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "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",
                  "null"
                ]
              },
              "max_turns": {
                "format": "uint32",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "max_validation_retries": {
                "format": "uint32",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "partial_result_available": {
                "type": [
                  "boolean",
                  "null"
                ]
              },
              "pending_function_calls": {
                "items": {
                  "type": "string"
                },
                "type": [
                  "array",
                  "null"
                ]
              },
              "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",
                  "null"
                ]
              },
              "result": true,
              "result_error": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "session_id": {
                "type": "string"
              },
              "status": {
                "$ref": "#/definitions/TurnStatus"
              },
              "step": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "stop_reason": {
                "default": null,
                "description": "Why a `completed` turn stopped when the model did not end it itself (`max_turns`). Present in the lean report too: a poller that reads `completed` with no error must still be able to tell an exhausted budget from a finished task.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "transient_resumes": {
                "format": "uint32",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              },
              "turn_count": {
                "format": "uint32",
                "minimum": 0,
                "type": "integer"
              },
              "turn_id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "validation_retries": {
                "format": "uint32",
                "minimum": 0,
                "type": [
                  "integer",
                  "null"
                ]
              }
            },
            "required": [
              "children",
              "session_id",
              "status",
              "step",
              "turn_count"
            ],
            "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": {}
    }
  ]
}