Plugins
Plugins allow you to change the typical behavior of an agent. They enable you to introduce concepts like Skills, steering, or other behavioral modifications into the agentic loop. Plugins work by taking advantage of the low-level primitives exposed by the Agent class—model, system_prompt, messages, tools, and hooks—and executing logic to improve an agent’s behavior.
The Strands SDK provides built-in plugins that you can use out of the box:
- Skills - On-demand, modular instructions that agents discover and activate at runtime following the Agent Skills specification
- Steering - Modular prompting for complex agent tasks through context-aware guidance
You can also build and distribute your own plugins to extend agent functionality. See Get Featured to share your plugins with the community.
Using Plugins
Section titled “Using Plugins”Plugins are passed to agents during initialization via the plugins parameter:
from strands import Agentfrom strands.vended_plugins.steering import LLMSteeringHandler
# Create an agent with pluginsagent = Agent( tools=[my_tool], plugins=[LLMSteeringHandler(system_prompt="Guide the agent...")])// Plugins are not yet available in TypeScript SDKBuilding Plugins
Section titled “Building Plugins”This section walks through how to build a custom plugin step by step.
Basic Plugin Structure
Section titled “Basic Plugin Structure”A plugin is a class that extends the Plugin base class and defines a name property. For example, a simple logging plugin would look like this:
from strands import Agent, toolfrom strands.plugins import Plugin, hookfrom strands.hooks import BeforeToolCallEvent, AfterToolCallEvent
class LoggingPlugin(Plugin): """A plugin that logs all tool calls and provides a utility tool."""
name = "logging-plugin"
@hook def log_before_tool(self, event: BeforeToolCallEvent) -> None: """Called before each tool execution.""" print(f"[LOG] Calling tool: {event.tool_use['name']}") print(f"[LOG] Input: {event.tool_use['input']}")
@hook def log_after_tool(self, event: AfterToolCallEvent) -> None: """Called after each tool execution.""" print(f"[LOG] Tool completed: {event.tool_use['name']}")
@tool def debug_print(self, message: str) -> str: """Print a debug message.
Args: message: The message to print """ print(f"[DEBUG] {message}") return f"Printed: {message}"
# Using the pluginagent = Agent(plugins=[LoggingPlugin()])agent("Calculate 2 + 2 and print the result")// Plugins are not yet available in TypeScript SDKHow It Works Under the Hood
Section titled “How It Works Under the Hood”When you attach a plugin to an agent, the following happens:
- Discovery: The
Pluginbase class scans for methods decorated with@hookand@tool - Hook Registration: Each
@hookmethod is registered with the agent’s hook registry based on its event type hint - Tool Registration: Each
@toolmethod is added to the agent’s tools list - Initialization: The
init_agent(agent)method is called for any custom setup
flowchart TD A[Plugin Attached] --> B[Scan for @hook methods] A --> C[Scan for @tool methods] B --> D[Register hooks with agent] C --> E[Add tools to agent] D --> F[init_agent called] E --> F F --> G[Plugin Ready]The @hook Decorator
Section titled “The @hook Decorator”The @hook decorator marks methods as hook callbacks. The event type is automatically inferred from the type hint:
from strands.plugins import Plugin, hookfrom strands.hooks import BeforeModelCallEvent, AfterModelCallEvent
class ModelMonitorPlugin(Plugin): name = "model-monitor"
@hook def before_model(self, event: BeforeModelCallEvent) -> None: """Event type inferred from type hint.""" print("Model call starting...")
@hook def on_model_event(self, event: BeforeModelCallEvent | AfterModelCallEvent) -> None: """Handle multiple event types with a union.""" print(f"Model event: {type(event).__name__}")// Plugins are not yet available in TypeScript SDKManual Hook and Tool Registration
Section titled “Manual Hook and Tool Registration”For more control, you can manually register hooks and tools in the init_agent method:
from strands.plugins import Pluginfrom strands.hooks import BeforeToolCallEvent
class ManualPlugin(Plugin): name = "manual-plugin"
def __init__(self, verbose: bool = False): super().__init__() self.verbose = verbose
def init_agent(self, agent: "Agent") -> None: # Conditionally register additional hooks if self.verbose: agent.add_hook(self.verbose_log, BeforeToolCallEvent)
# Access agent properties print(f"Attached to agent with {len(agent.tool_names)} tools")
def verbose_log(self, event: BeforeToolCallEvent) -> None: print(f"[VERBOSE] {event.tool_use}")// Plugins are not yet available in TypeScript SDKManaging Plugin State
Section titled “Managing Plugin State”Plugins can maintain state that persists across agent invocations. For state that needs to be serialized or shared, use the Agent State mechanism:
from strands import Agentfrom strands.plugins import Plugin, hookfrom strands.hooks import BeforeToolCallEvent, AfterToolCallEvent
class MetricsPlugin(Plugin): """Track tool execution metrics using agent state."""
name = "metrics-plugin"
def init_agent(self, agent: "Agent") -> None: # Initialize state values if not present if "metrics_call_count" not in agent.state: agent.state.set("metrics_call_count", 0)
@hook def count_calls(self, event: BeforeToolCallEvent) -> None: current = event.agent.state.get("metrics_call_count", 0) event.agent.state.set("metrics_call_count", current + 1)
# Usageagent = Agent(plugins=[MetricsPlugin()])agent("Do some work")print(f"Tool calls: {agent.state.get('metrics_call_count')}")// Plugins are not yet available in TypeScript SDKSee Agent State for more information on state management.
Async Plugin Initialization
Section titled “Async Plugin Initialization”Plugins can perform asynchronous initialization:
import asynciofrom strands.plugins import Plugin, hookfrom strands.hooks import BeforeToolCallEvent
class AsyncConfigPlugin(Plugin): name = "async-config"
async def init_agent(self, agent: "Agent") -> None: # Async initialization self.config = await self.load_config()
async def load_config(self) -> dict: await asyncio.sleep(0.1) # Simulate async operation return {"setting": "value"}
@hook def use_config(self, event: BeforeToolCallEvent) -> None: print(f"Config: {self.config}")// Plugins are not yet available in TypeScript SDKNext Steps
Section titled “Next Steps”- Hooks - Learn about the underlying hook system
- Steering - Explore the built-in steering plugin
- Get Featured - Share your plugins with the community