Playbooks¶
Structured execution plans for agents — declared step sequences with
expected tools, validation criteria, and guidance hints. When attached
via AgentConfig.playbook, the PlaybookEnforcerHook (the
HookProvider the agent installs automatically) drives a
PlaybookEnforcer engine that gates each tool call against the
current step and auto-advances when the step's expected_tools are
exhausted.
Models¶
Playbook ¶
PlaybookStep ¶
Bases: BaseModel
Individual step in a playbook.
Defines what tools are expected, hints for the agent, and optional validation criteria.
PlaybookPlan ¶
StepExecution ¶
Bases: BaseModel
Record of a single step's execution.
StepStatus ¶
Bases: StrEnum
Status of a playbook step.
Loader¶
load_playbook ¶
Load a playbook from various sources.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source
|
str | Path | dict[str, Any]
|
Path to file, JSON string, or dictionary |
required |
Returns:
| Type | Description |
|---|---|
Playbook
|
Loaded and validated Playbook |
Examples:
>>> playbook = load_playbook("./playbooks/deploy.yaml")
>>> playbook = load_playbook({"id": "test", "name": "Test", "steps": []})
Source code in .sdk/src/tulip/playbooks/loader.py
PlaybookLoader ¶
Load playbooks from JSON and YAML files.
Supports loading from: - JSON files (.json) - YAML files (.yaml, .yml) - Dictionaries (for programmatic use)
load_file ¶
Load a playbook from a file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str | Path
|
Path to the playbook file (.json, .yaml, or .yml) |
required |
Returns:
| Type | Description |
|---|---|
Playbook
|
Loaded and validated Playbook |
Raises:
| Type | Description |
|---|---|
PlaybookLoadError
|
If file cannot be loaded or validated |
Source code in .sdk/src/tulip/playbooks/loader.py
load_dict ¶
Load a playbook from a dictionary.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
dict[str, Any]
|
Dictionary containing playbook definition |
required |
Returns:
| Type | Description |
|---|---|
Playbook
|
Loaded and validated Playbook |
Raises:
| Type | Description |
|---|---|
PlaybookLoadError
|
If data is invalid |
Source code in .sdk/src/tulip/playbooks/loader.py
load_json_string ¶
Load a playbook from a JSON string.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
json_string
|
str
|
JSON string containing playbook definition |
required |
Returns:
| Type | Description |
|---|---|
Playbook
|
Loaded and validated Playbook |
Raises:
| Type | Description |
|---|---|
PlaybookLoadError
|
If JSON is invalid or playbook validation fails |
Source code in .sdk/src/tulip/playbooks/loader.py
load_yaml_string ¶
Load a playbook from a YAML string.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
yaml_string
|
str
|
YAML string containing playbook definition |
required |
Returns:
| Type | Description |
|---|---|
Playbook
|
Loaded and validated Playbook |
Raises:
| Type | Description |
|---|---|
PlaybookLoadError
|
If YAML is invalid or playbook validation fails |
Source code in .sdk/src/tulip/playbooks/loader.py
PlaybookLoadError ¶
Enforcer¶
PlaybookEnforcer is the enforcement engine that holds the model to
the playbook's step sequence. PlaybookEnforcerHook is the
HookProvider wrapper around it, installed automatically when
AgentConfig.playbook is set.
PlaybookEnforcer ¶
Bases: BaseModel
Enforces playbook execution sequence and constraints.
The enforcer tracks progress through a playbook, validates tool calls, and provides hints to guide the agent through the execution plan.
Features: - Track completed steps - Validate tool calls match current step's expected tools - Provide hints for the next step - Block out-of-sequence execution when strict_sequence is True - Record violations for auditing
from_playbook
classmethod
¶
from_playbook(playbook: Playbook, block_violations: bool = True, record_violations: bool = True) -> PlaybookEnforcer
Create an enforcer from a playbook.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
playbook
|
Playbook
|
The playbook to enforce |
required |
block_violations
|
bool
|
Whether to block violating tool calls |
True
|
record_violations
|
bool
|
Whether to record violations |
True
|
Returns:
| Type | Description |
|---|---|
PlaybookEnforcer
|
Configured PlaybookEnforcer |
Source code in .sdk/src/tulip/playbooks/enforcer.py
validate_tool_call ¶
Validate a tool call against the current step.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tool_name
|
str
|
Name of the tool being called |
required |
Returns:
| Type | Description |
|---|---|
EnforcementResult
|
EnforcementResult indicating whether the call is allowed |
Source code in .sdk/src/tulip/playbooks/enforcer.py
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 | |
record_tool_call ¶
Record that a tool was called.
Updates the step execution tracking.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tool_name
|
str
|
Name of the tool that was called |
required |
Source code in .sdk/src/tulip/playbooks/enforcer.py
complete_current_step ¶
Mark the current step as complete and advance.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
result
|
str | None
|
Optional result to record for the step |
None
|
Returns:
| Type | Description |
|---|---|
bool
|
True if advanced to next step, False if playbook is complete |
Source code in .sdk/src/tulip/playbooks/enforcer.py
skip_current_step ¶
Skip the current step.
Only works for non-required steps.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
reason
|
str | None
|
Optional reason for skipping |
None
|
Returns:
| Type | Description |
|---|---|
bool
|
True if step was skipped, False if step is required |
Source code in .sdk/src/tulip/playbooks/enforcer.py
fail_current_step ¶
Mark the current step as failed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
error
|
str
|
Error message |
required |
Source code in .sdk/src/tulip/playbooks/enforcer.py
get_next_step_hints ¶
Get hints for the next step after current.
Useful for looking ahead during execution.
Returns:
| Type | Description |
|---|---|
list[str]
|
List of hints for the next step, or empty if no next step |
Source code in .sdk/src/tulip/playbooks/enforcer.py
get_step_summary ¶
Get a summary of step execution status.
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
Dictionary with step status summary |
Source code in .sdk/src/tulip/playbooks/enforcer.py
reset ¶
Reset the enforcer to start over.
Source code in .sdk/src/tulip/playbooks/enforcer.py
EnforcementResult ¶
Bases: BaseModel
Result of an enforcement check.
EnforcementViolation ¶
Bases: BaseModel
Record of an enforcement violation.
PlaybookEnforcerHook ¶
PlaybookEnforcerHook(playbook: Playbook, *, block_violations: bool = True, record_violations: bool = True, priority: int = HookPriority.SECURITY_DEFAULT)
Bases: HookProvider
Hook that enforces a :class:Playbook over an agent run.
Holds a single :class:PlaybookEnforcer instance and dispatches
before/after_tool_call events into it so step compliance is tracked
automatically. Auto-advances to the next step when the current step's
expected tool list is exhausted.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
playbook
|
Playbook
|
The playbook to enforce. A fresh |
required |
block_violations
|
bool
|
When True (default), a violating tool call is
cancelled via |
True
|
record_violations
|
bool
|
When True (default), violations land on
|
True
|
priority
|
int
|
Hook priority. Defaults to a high value so the enforcer runs before observability / retry hooks; that way a blocked tool call doesn't get logged as if it had executed. |
SECURITY_DEFAULT
|
Example
from tulip import Agent from tulip.playbooks.loader import load_playbook from tulip.playbooks.hook import PlaybookEnforcerHook
playbook = load_playbook("playbooks/triage.yaml") agent = Agent( model="openai:gpt-4o", tools=[search, classify, escalate], hooks=[PlaybookEnforcerHook(playbook)], ) result = agent.run_sync("Triage this incident.")
Source code in .sdk/src/tulip/playbooks/hook.py
enforcer
property
¶
Return the underlying enforcer for inspection (violations, progress).
on_before_tool_call
async
¶
Validate the call against the current step; cancel on violation.
Source code in .sdk/src/tulip/playbooks/hook.py
on_after_tool_call
async
¶
Record the call and auto-advance when the current step is satisfied.
The agent loop short-circuits past on_after_tool_call when the
before-hook cancelled the call, so anything reaching this method
actually executed.
Source code in .sdk/src/tulip/playbooks/hook.py
on_before_invocation
async
¶
Called before agent starts processing.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
prompt
|
str
|
The user prompt being processed |
required |
state
|
AgentState
|
Current agent state |
required |
Returns:
| Type | Description |
|---|---|
AgentState
|
Potentially modified agent state |
Source code in .sdk/src/tulip/hooks/provider.py
on_after_invocation
async
¶
Called after agent completes processing.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
state
|
AgentState
|
Final agent state |
required |
success
|
bool
|
Whether execution completed successfully |
required |
Source code in .sdk/src/tulip/hooks/provider.py
on_iteration_start
async
¶
Called at the start of each agent iteration.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
iteration
|
int
|
Current iteration number (0-indexed) |
required |
state
|
AgentState
|
Current agent state |
required |
Source code in .sdk/src/tulip/hooks/provider.py
on_iteration_end
async
¶
Called at the end of each agent iteration.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
iteration
|
int
|
Current iteration number (0-indexed) |
required |
state
|
AgentState
|
Current agent state |
required |
Source code in .sdk/src/tulip/hooks/provider.py
on_before_model_call
async
¶
Called before each model.complete() call.
Modify event.messages to change what the model sees. event.tools is read-only (inspect only).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
event
|
BeforeModelCallEvent
|
Write-protected event. Writable: messages. |
required |
Source code in .sdk/src/tulip/hooks/provider.py
on_after_model_call
async
¶
Called after each model.complete() call.
Set event.retry = True to discard response and re-call. Set event.response to replace the response. event.messages is read-only.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
event
|
AfterModelCallEvent
|
Write-protected event. Writable: response, retry. |
required |
Source code in .sdk/src/tulip/hooks/provider.py
register_hooks ¶
Return which hooks this provider implements.
Returns:
| Type | Description |
|---|---|
dict[str, bool]
|
Dictionary mapping hook names to whether they are implemented. |
dict[str, bool]
|
Useful for optimization - registry can skip calling unimplemented hooks. |