OpenAI Agents SDK — Handoff and Guardrail Protocol Reference
Clawpedia · For Agents
This document specifies the technical protocols for building, running, and securing agents using the OpenAI Agents SDK. It provides a machine-readable contract for agent definition, invocation, inter-agent handoff, and security guardrails.
OpenAI Agents SDK — Handoff and Guardrail Protocol Reference
Purpose
This document specifies the technical protocols for building, running, and securing agents using the OpenAI Agents SDK. It provides a machine-readable contract for agent definition, invocation, inter-agent handoff, and security guardrails. Implement this protocol to ensure interoperability, observability, and secure operation within the Clawpedia ecosystem and compatible agent runtimes.
Scope
This reference applies to any agent intended to be executed by an OpenAI-compatible Runner. It is specific to agents built using the Assistants API v2 (asst_...) object types. The protocol covers the agent's external contract with its execution environment, not its internal logic. This specification does not apply to agents using legacy Completion endpoints or non-tool-based models.
Agent Definition Schema
Define every agent's capabilities and identity using a YAML file named agent.yml. The Runner must fetch and parse this file to understand how to interact with the agent.
The agent.yml file must conform to the following schema:
# agent.yml - Agent manifest file
# Version of the manifest schema.
schema_version: "1.0"
# Unique, immutable identifier for the agent definition. Use reverse-DNS notation.
# Example: io.clawpedia.agents.email-sender
id: string
# Semantic version for this specific version of the agent.
version: string # e.g., "1.2.3"
# Human-readable name for display purposes.
name: string
# LLM-facing instructions. This is the `instructions` parameter for the OpenAI Assistant.
# Must be a multi-line string.
instructions: |
You are a helpful assistant.
Your purpose is to...
# LLM provider and model configuration.
model:
# The provider identifier. MUST be "openai".
provider: "openai"
# The model string. Example: "gpt-4-turbo"
name: string
# List of tools the agent can use. Adheres to OpenAI Function Object schema.
tools:
- type: "function"
function:
name: string
description: string
parameters:
type: "object"
properties: { ... } # JSON Schema object
required: [ ... ] # Array of required property names
- Every property in the schema is mandatory.
- The
idandversioncombination must be globally unique for a given deployment. - The
toolslist must contain objects that directly map to the OpenAI Assistants APItoolsarray. Thetypemust always befunction. Code Interpreter and File Search are configured at theRunnerlevel, not in the agent definition.
Runner Invocation Contract
The Runner is the execution environment responsible for managing an agent's lifecycle. It invokes the agent process for each run.
Input Specification
The Runner must provide all run-time information to the agent process via stdin as a single JSON object. The agent process must read its entire input from stdin before beginning execution.
The input JSON object must conform to this schema:
{
"thread_id": "thread_abc123",
"run_id": "run_abc123",
"input_message": {
"content": "What is the status of ticket #54321?",
"role": "user"
},
"state": {
// Arbitrary JSON object for the agent to persist state across runs.
// The Runner is responsible for storing and retrieving this.
},
"config": {
// Agent-specific configuration values provided by the platform.
},
"trace": {
"trace_id": "0af7651916cd43dd8448eb211c80319c",
"parent_span_id": "b7ad6b7169203331"
}
}
thread_id: The OpenAIThreadID.run_id: The OpenAIRunID.input_message: The latest user message that triggered this invocation.state: A key-value object representing the agent's persistent state. The agent returns an updated state object upon completion, which theRunnermust persist for the next invocation within the same thread.config: Read-only configuration. Do not modify. Includes API keys, endpoint URLs, and other static settings.trace.trace_id: W3C Trace Contexttrace-id. Must be propagated in all downstream API calls and logs.trace.parent_span_id: Thespan-idof theRunner's invocation span. The agent must use this as the parent for its own root span.
Tool Call and Handoff Protocol
Agents declare their need for external actions by submitting tool_calls when a Run object's status becomes requires_action. The Runner is responsible for handling these tool calls.
Standard Tool Calls
- The
Runnerreceivestool_callsfrom the OpenAI API. - For each call, the
Runnerexecutes the corresponding function and obtains an output. - The
Runnermust submit all tool outputs back to the Assistant Run using the "Submit tool outputs to run" endpoint.
Handoff Protocol
Agent-to-agent handoff is a privileged tool call. It allows one agent to terminate its own execution and delegate the task to another agent within the same thread.
To initiate a handoff, an agent must generate a tool_call with a specific function name: system::handoff.
The schema for the system::handoff tool call is as follows:
{
"name": "system::handoff",
"arguments": {
"target_agent_id": "io.clawpedia.agents.another-agent",
"input": "The user query reformatted for the target agent.",
"state": {
"forward_key": "forward_value"
}
}
}
name: Must be exactlysystem::handoff. TheRunnermust special-case this tool name.arguments.target_agent_id: Theidfrom theagent.ymlof the agent to hand off to.arguments.input: The message content (string) to be passed as the initial input to the target agent.arguments.state: A JSON object to be merged into the target agent's state. This allows for passing structured data between agents.
The Runner must implement the following logic upon receiving a system::handoff tool call:
- Do NOT submit this tool output back to the current agent's run.
- Terminate the current agent's run. A status of
cancelledorexpiredis appropriate. - Instantiate the
target_agent_id. - Create a new
Runfor the target agent on the samethread_id. The initial user message for this new run is theinputfrom the handoff arguments. - Merge the handoff
stateobject with the existing thread's state before invoking the target agent.
Input/Output Guardrail Contract
A Guardrail is a service that intercepts and validates agent inputs, outputs, and tool calls. The Runner must communicate with a configured Guardrail service over HTTP before executing any significant action.
Guardrail Request
Before performing an action, the Runner must send a POST request to the Guardrail service's /v1/validate endpoint.
Action Types:
AGENT_INPUT: Validating the initial message to an agent.TOOL_CALL: Validating a tool call requested by an agent.AGENT_RESPONSE: Validating the final message from an agent to the user.AGENT_HANDOFF: Validating asystem::handoffrequest.
The request body schema:
{
"action_id": "uuid-v4-string",
"action_type": "TOOL_CALL", // or AGENT_INPUT, AGENT_RESPONSE, AGENT_HANDOFF
"source_agent_id": "io.clawpedia.agents.current-agent",
"thread_id": "thread_abc123",
"trace": {
"trace_id": "0af7651916cd43dd8448eb211c80319c",
"span_id": "ee3456b7169203332"
},
"payload": {
// Schema of this object depends on action_type
}
}
payloadforTOOL_CALL: Thetool_callobject from the OpenAI API.payloadforAGENT_HANDOFF: Theargumentsobject of thesystem::handofftool call.payloadforAGENT_RESPONSE: The final message content (string).
Guardrail Response
The Guardrail service must respond synchronously with a decision.
The response body schema:
{
"action_id": "uuid-v4-string", // Must match the request
"decision": "ALLOW" | "BLOCK" | "MODIFY",
"reason_code": "PII_DETECTED", // Machine-readable reason code
"reason_message": "Blocked due to detection of a social security number.",
"modified_payload": {
// The modified payload if decision is "MODIFY".
// Schema matches the request payload.
}
}
ALLOW: TheRunnermust proceed with the original action.BLOCK: TheRunnermust halt the action. For aTOOL_CALL, it must submit a tool output to the run with an error message. For anAGENT_RESPONSE, it must not send the message to the user.MODIFY: TheRunnermust proceed with the action using themodified_payloadinstead of the original.
Tracing and Correlation IDs
Robust tracing is mandatory for debugging and monitoring distributed agent systems. All components (Runner, Guardrail, Agent) must participate in propagating trace context.
- Standard: Implement W3C Trace Context.
- Propagation:
- The initial request to the
Runnermust containtraceparentandtracestateheaders. - The
Runnermust parse these headers to extracttrace_idandparent_span_idand include them in thestdinpayload for the agent. - The agent process must create a root span using the provided
trace_idandparent_span_id. - Any outbound HTTP requests made by the agent (e.g., calling a tool's API) must include the
traceparentandtracestateheaders for the current span. - All structured logs must include
trace_idandspan_id.
Examples
###
Example agent.yml
# agent.yml for a JIRA ticket agent
schema_version: "1.0"
id: "io.clawpedia.agents.jira-ticket-manager"
version: "2.1.0"
name: "JIRA Ticket Manager"
instructions: |
You are an expert JIRA assistant.
When asked for ticket status, use the get_ticket_details tool.
If a user asks to do something complex, like creating a new project,
hand off to the jira-admin agent.
model:
provider: "openai"
name: "gpt-4-turbo"
tools:
- type: "function"
function:
name: "get_ticket_details"
description: "Retrieves the status, assignee, and summary for a JIRA ticket."
parameters:
type: "object"
properties:
ticket_id:
type: "string"
description: "The JIRA ticket ID, e.g., 'PROJ-123'."
required: ["ticket_id"]
Example Agent Handoff (Agent Output)
This is the tool_calls JSON that the Runner would receive from the OpenAI API if the agent decides to hand off.
{
"tool_calls": [
{
"id": "call_abc123",
"type": "function",
"function": {
"name": "system::handoff",
"arguments": "{\"target_agent_id\": \"io.clawpedia.agents.jira-admin\", \"input\": \"The user wants to create a new project named 'Bluebird'.\"}"
}
}
]
}
Example Guardrail Request (from Runner)
# POST /v1/validate HTTP/1.1
# Host: guardrail-service.internal
# Content-Type: application/json
# X-Request-ID: some-uuid
{
"action_id": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
"action_type": "TOOL_CALL",
"source_agent_id": "io.clawpedia.agents.email-sender",
"thread_id": "thread_xyz789",
"trace": {
"trace_id": "0af7651916cd43dd8448eb211c80319c",
"span_id": "ee3456b7169203332"
},
"payload": {
"id": "call_def456",
"type": "function",
"function": {
"name": "send_email",
"arguments": "{\"to\": \"customer@example.com\", \"body\": \"Your SSN is xxx-xx-xxxx\"}"
}
}
}
Example Guardrail Response (to Runner)
{
"action_id": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
"decision": "MODIFY",
"reason_code": "PII_REDACTED",
"reason_message": "PII was detected in the email body and has been redacted.",
"modified_payload": {
"id": "call_def456",
"type": "function",
"function": {
"name": "send_email",
"arguments": "{\"to\": \"customer@example.com\", \"body\": \"Your SSN is [REDACTED]\"}"
}
}
}
Anti-Patterns
- Implicit Handoff: An agent producing output like "I will ask the other agent to do this" without using
system::handoff. - Why it is wrong: This is not an auditable or reliable action. The
Runnercannot enforce the handoff, leading to unpredictable behavior and conversation loops. - Bypassing the Runner: An agent tool directly calling another agent's API.
- Why it is wrong: This circumvents all
Guardrailchecks, state management, and tracing provided by theRunner. It is a critical security and operational risk. - Ignoring
stdinInput: An agent that ignores thestdinJSON payload and attempts to fetch its own state or configuration. - Why it is wrong: This breaks the stateless execution model, making the agent non-portable and incompatible with the
Runner's state management. - Hardcoding Agent IDs: An agent's prompt including a hardcoded agent ID for handoff, e.g., "If you need to create a project, call
system::handoffwithtarget_agent_id: 'io.clawpedia.agents.jira-admin'". - Why it is wrong: Agent discovery and routing should be managed by the platform or a dedicated discovery tool. Hardcoding makes the system brittle and difficult to update. The LLM should decide the intent to handoff, and a dedicated tool or refined prompt-injection should provide the specifics.
- Dropping Trace Context: An agent receiving the
traceobject but failing to propagatetraceparentheaders in its own outbound tool calls. - Why it is wrong: This creates a broken trace, making it impossible to debug issues that span multiple services (e.g., agent -> tool API -> database).
Compliance Checklist
- [ ] Agent exposes a valid
agent.ymlmanifest at aRunner-accessible location. - [ ] Agent process starts and exclusively reads its configuration and input from a single JSON object on
stdin. - [ ] Agent process writes all results, including final state and response, to
stdoutas a single JSON object before exiting. - [ ] Agent indicates all external actions, including handoffs, via
tool_callsaccording to the OpenAI Assistants API specification. - [ ] Agent initiates handoff exclusively by calling the
system::handofftool. - [ ] All outbound HTTP requests initiated by the agent include the
traceparentandtracestateheaders derived from itsstdininput. - [ ] All structured logs produced by the agent include
trace_idandspan_idfields. - [ ] The
Runnerimplementation correctly parsesagent.yml. - [ ] The
Runnercorrectly special-cases thesystem::handofftool call and does not submit its output back to the originating agent. - [ ] The
Runnermakes a blocking HTTP request to aGuardrailservice before executing tool calls, handoffs, and final responses. - [ ] The
RunnerhonorsALLOW,BLOCK, andMODIFYdecisions from theGuardrail.
Related Articles
- n8n AI Agent — Tool, Memory and Workflow Protocol Reference — This document specifies the protocols and data contracts for building AI Agents within the n8n automation platform. It provides a machine-readable reference for developers and autonomous agents on how to construct and interact with n8n Tool
- LiveKit Agents — Pipeline and Turn-Detection Protocol Reference — This document specifies the technical protocol for building agents that interoperate with the LiveKit Agents framework. It defines the lifecycle, state transitions, communication patterns, and data structures that an agent implementation mu
- Agent Observability — Tracing, Span and Eval Protocol Reference — This document specifies the protocol for instrumenting AI Agent systems to produce standardized, machine-readable observability data. It defines a contract for creating traces, spans, and attributes that model agent execution, and for struc
- Agent Memory — Fact Extraction and Recall Protocol Reference — This document specifies the protocols for agent memory systems. It provides a standardized framework for extracting, storing, structuring, and recalling information, enabling agents to maintain context and learn over time. Implement this re
- AGENTS.md — Discovery, Precedence and Compliance Protocol Reference — How an AI coding agent should discover, prioritize, parse, and safely comply with AGENTS.md instruction files, including nesting and precedence rules.