The lightweight foundation for building agents
Stirrup is a lightweight framework, or starting point template, for building agents. It differs from other agent frameworks by:
- **Working with the model, not against it:** Stirrup gets out of the way and lets the model choose its own approach to completing tasks (similar to Claude Code). Many frameworks impose rigid workflows that can degrade results.
- **Best practices and tools built-in:** We analyzed the leading agents (Claude Code, Codex, and others) to understand and incorporate best practices relating to topics like context management and foundational tools (e.g., code execution).
- **Fully customizable:** Use Stirrup as a package or as a starting template to build your own fully customized agents.
> **Note:** This is the Python implementation, [StirrupJS](https://github.com/ArtificialAnalysis/StirrupJS) is the Typescript implementation.
## Features
- ๐งช **Code execution:** Run code locally, in Docker, or in an E2B sandbox
- ๐ **Online search / web browsing:** Search and fetch web pages
- ๐ **MCP client support:** Connect to MCP servers and use their tools/resources
- ๐ **Document input and output:** Import files into context and produce file outputs
- ๐งฉ **Skills system:** Extend agents with modular, domain-specific instruction packages
- ๐ ๏ธ **Flexible tool execution:** A generic `Tool` interface allows easy tool definition
- ๐ค **Human-in-the-loop:** Includes a built-in user input tool that enables human feedback or clarification during agent execution
- ๐ง **Context management:** Automatically summarizes conversation history when approaching context limits
- ๐ **Flexible provider support:** Pre-built support for OpenAI-compatible APIs, LiteLLM, or bring your own client
- ๐ผ๏ธ **Multimodal support:** Process images, video, and audio with automatic format conversion
## Installation
```bash
# Core framework
pip install stirrup # or: uv add stirrup
# With all optional components
pip install 'stirrup[all]' # or: uv add 'stirrup[all]'
# Individual extras
pip install 'stirrup[litellm]' # or: uv add 'stirrup[litellm]'
pip install 'stirrup[docker]' # or: uv add 'stirrup[docker]'
pip install 'stirrup[e2b]' # or: uv add 'stirrup[e2b]'
pip install 'stirrup[mcp]' # or: uv add 'stirrup[mcp]'
pip install 'stirrup[browser]' # or: uv add 'stirrup[browser]'
```
## Quick Start
```python
import asyncio
from stirrup import Agent
from stirrup.clients.chat_completions_client import ChatCompletionsClient
async def main() -> None:
"""Run an agent that searches the web and creates a chart."""
# Create client using ChatCompletionsClient
# Automatically uses OPENROUTER_API_KEY environment variable
client = ChatCompletionsClient(
base_url="https://openrouter.ai/api/v1",
model="anthropic/claude-sonnet-4.5",
)
# As no tools are provided, the agent will use the default tools, which consist of:
# - Web tools (web search and web fetching, note web search requires BRAVE_API_KEY)
# - Local code execution tool (to execute shell commands)
agent = Agent(client=client, name="agent", max_turns=15)
# Run with session context - handles tool lifecycle, logging and file outputs
async with agent.session(output_dir="./output/getting_started_example") as session:
finish_params, history, metadata = await session.run(
"""
What is the population of Australia over the last 3 years? Search the web to find out and create a
simple chart using matplotlib showing the current population per year."""
)
print("Finish params: ", finish_params)
print("History: ", history)
print("Metadata: ", metadata)
if __name__ == "__main__":
asyncio.run(main())
```
> **Note:** This example uses OpenRouter. Set `OPENROUTER_API_KEY` in your environment before running. Web search requires a `BRAVE_API_KEY`. The agent will still work without it, but web search will be unavailable.
## Full Customization
For using Stirrup as a foundation for your own fully customized agent, you can clone and import Stirrup locally:
```bash
# Clone the repository
git clone https://github.com/ArtificialAnalysis/Stirrup.git
cd stirrup
# Install in editable mode
pip install -e . # or: uv venv && uv pip install -e .
# Or with all optional dependencies
pip install -e '.[all]' # or: uv venv && uv pip install -e '.[all]'
```
See the [Full Customization guide](https://stirrup.artificialanalysis.ai/extending/full-customization/) for more details.
## How It Works
- **`Agent`** - Configures and runs the agent loop until a finish tool is called or max turns reached
- **`session()`** - Context manager that sets up tools, manages files, and handles cleanup
- **`Tool`** - Define tools with Pydantic parameters
- **`ToolProvider`** - Manage tools that require lifecycle (connections, temp directories, etc.)
- **`DEFAULT_TOOLS`** - Standard tools included by default: code execution and web tools
## Using Other LLM Providers
For non-OpenAI providers, change the base URL of the `ChatCompletionsClient`, use the `LiteLLMClient` (requires installation of optional `stirrup[litellm]` dependencies), or create your own client.
### OpenAI-Compatible APIs
```python
# Create client using Deepseek's OpenAI-compatible endpoint
client = ChatCompletionsClient(
base_url="https://api.deepseek.com",
model="deepseek-chat", # or "deepseek-reasoner" for R1
api_key=os.environ["DEEPSEEK_API_KEY"],
)
agent = Agent(client=client, name="deepseek_agent")
```
### LiteLLM (Anthropic, Google, etc.)
```python
# Ensure LiteLLM is added with: pip install 'stirrup[litellm]' # or: uv add 'stirrup[litellm]'
# Create LiteLLM client for Anthropic Claude
# See https://docs.litellm.ai/docs/providers for all supported providers
client = LiteLLMClient(
model_slug="anthropic/claude-sonnet-4-5",
max_tokens=200_000,
)
# Pass client to Agent - model info comes from client.model_slug
agent = Agent(
client=client,
name="claude_agent",
)
```
See [LiteLLM Example](https://stirrup.artificialanalysis.ai/examples/#litellm-multi-provider-support) or [Deepseek Example](https://stirrup.artificialanalysis.ai/examples/#openai-compatible-apis-deepseek-vllm-ollama) for complete examples.
## Default Tools
When you create an `Agent` without specifying tools, it uses `DEFAULT_TOOLS`:
| Tool Provider | Tools Provided | Description |
| --------------------------- | ------------------------- | ------------------------------------------------------------ |
| `LocalCodeExecToolProvider` | `code_exec` | Execute shell commands in an isolated temp directory |
| `WebToolProvider` | `web_fetch`, `web_search` | Fetch web pages and search (search requires `BRAVE_API_KEY`) |
## Extending with Pre-Built Tools
```python
import asyncio
from stirrup import Agent
from stirrup.clients.chat_completions_client import ChatCompletionsClient
from stirrup.tools import CALCULATOR_TOOL, DEFAULT_TOOLS
# Create client for OpenRouter
client = ChatCompletionsClient(
base_url="https://openrouter.ai/api/v1",
model="anthropic/claude-sonnet-4.5",
)
# Create agent with default tools + calculator tool
agent = Agent(
client=client,
name="web_calculator_agent",
tools=[*DEFAULT_TOOLS, CALCULATOR_TOOL],
)
```
## Defining Custom Tools
```python
from pydantic import BaseModel, Field
from stirrup import Agent, Tool, ToolResult, ToolUseCountMetadata
from stirrup.clients.chat_completions_client import ChatCompletionsClient
from stirrup.tools import DEFAULT_TOOLS
class GreetParams(BaseModel):
"""Parameters for the greet tool."""
name: str = Field(description="Name of the person to greet")
formal: bool = Field(default=False, description="Use formal greeting")
def greet(params: GreetParams) -> ToolResult[ToolUseCountMetadata]:
greeting = f"Good day, {params.name}." if params.formal else f"Hey {params.name}!"
return ToolResult(
content=greeting,
metadata=ToolUseCountMetadata(),
)
GREET_TOOL = Tool(
name="greet",
description="Greet someone by name",
parameters=GreetParams,
executor=greet,
)
# Create client for OpenRouter
client = ChatCompletionsClient(
base_url="https://openrouter.ai/api/v1",
model="anthropic/claude-sonnet-4.5",
)
# Add custom tool to default tools
agent = Agent(
client=client,
name="greeting_agent",
tools=[*DEFAULT_TOOLS, GREET_TOOL],
)
```
## Next Steps
- [Getting Started](https://stirrup.artificialanalysis.ai/getting-started/) - Installation and first agent tutorial
- [Core Concepts](https://stirrup.artificialanalysis.ai/concepts/) - Understand Agent, Tools, and Sessions
- [Examples](https://stirrup.artificialanalysis.ai/examples/) - Working examples for common patterns
- [Creating Tools](https://stirrup.artificialanalysis.ai/guides/tools/) - Build your own tools
## Documentation
Full documentation: [artificialanalysis.github.io/Stirrup](https://stirrup.artificialanalysis.ai)
Build and serve locally:
```bash
uv run mkdocs serve
```
## Development
```bash
# Format and lint code
uv run ruff format
uv run ruff check
# Type check
uv run ty check
# Run tests
uv run pytest tests
```
## License
Licensed under the [MIT LICENSE](LICENSE).