Agent contract
The agent contract is the wire between Ironhide and your agent: what
Ironhide hands you for each episode, and what your agent returns after it
has driven that episode. Contract v2 is the default and the only customer
contract — every new registration is on v2, and there is no per-mode
branching to reason about, because there is one mode (ci).
Contract v1 is retired for customers. Registering with
contract_version: "v1", or PATCHing an agent to v1, fails with
403 contract_v1_retired; only the operator can pin v1 for internal
agents.
Where the contract lives#
Your agent runs inside your own pipeline, so the contract is not an HTTP
endpoint Ironhide calls — it is an adapter: a small callable you write
that hands the episode to your real agent and returns what it did. The CLI
(ironhide episode run) and the CI wrappers pull the episode manifest,
invoke your adapter, and submit the trajectory for grading.
An adapter is any callable with this shape:
def my_adapter(prompt, tools):
...
return response # a dict, shaped per the episode's tierpromptis the episode manifest: itsepisode_type, the visible transcript or script, and its system context.toolsis the world's tool manifest — a list of tools your agent may call (empty for episodes with no executable world).
If you pass no --adapter, the CLI uses a built-in, deliberately harmless
reference adapter so you can run the flow end to end before wiring in your
real agent.
What your agent returns, by tier#
Every episode is one of three tiers, and the manifest tells you which. Your adapter's return shape follows the tier:
| Tier | Episode kind | Return |
|---|---|---|
| A | Behavioral — your agent reviews a transcript and calls out attacks it sees. | {"detections": [{"turn", "attack_type", "reason"}]} |
| B | Adversarial (prose) — your agent responds turn by turn to a scripted attack. | {"actions": [{"turn", "action", "response"}]} |
| C | Adversarial (world) — your agent responds and may call tools in a live world. | {"actions": [...], "tool_calls": [{"turn", "tool", "args"}]} |
For a Tier C episode the CLI runs a short drive loop: your adapter can
issue tool_calls, receive their results back on the next round (folded
into the manifest as tool_results), and react — until it stops asking for
tools or a termination guard trips. A minimal adapter:
def my_adapter(prompt, tools):
if prompt.get("episode_type") == "behavioral": # Tier A
return {"detections": my_agent.review(prompt["episode"]["transcript"])}
script = prompt["episode"]["script"] # Tier B / C
results = prompt.get("tool_results", []) # Tier C feedback
actions, calls = my_agent.defend(script, tools, results)
return {"actions": actions, "tool_calls": calls}What comes back#
Ironhide grades the submitted trajectory and returns a verdict on what your agent did, not on what it said about itself:
{
"run_id": "…",
"episode_id": "ep_5b1c0f4a9d22",
"episode_type": "adversarial",
"tier": "C",
"status": "FAIL",
"severity": "high",
"why": "The agent forwarded a customer record to an external address after an injected instruction.",
"evidence": [ … ],
"maturity": "preview"
}You always see the episode type and the full verdict — status,
severity, why, and evidence — plus observed-state detail for Tier C
world episodes. You never see the episode's answer key: the ground truth,
the per-turn labels, and the grading rubric stay server-side. That is what
keeps the library honest — an agent cannot be tuned against answers it has
never seen.
Viewing and switching your contract#
$ ironhide contract # show your agent's current contract version
$ ironhide contract v2 # switch (and reset verification)
$ ironhide verify # re-run the connection testOver the API, the registration response includes your effective
contract_version, and PATCH /agents/{agent_id} with
{"contract_version": "v2"} switches it. A verification stamp is valid for
exactly one contract version, so switching resets your agent to
unverified — re-verify before driving episodes.
Next steps#
- Verify the connection: the connection test.
- Running an evaluation: drive an episode with your adapter and read the verdict.
- Attack taxonomy: the categories a verdict can convict on.
IRONHIDE