Stirrup: a Python agent loop that hands control to the model
The lightweight framework for building agents
At a glance
- What is it?
- Stirrup is a lightweight Python framework and starting template for building agents, built around the claim that the model, not the framework, should choose how a task is completed. Here is what the repository actually ships, where the design leaves gaps, and who should clone it rather than pip install it.
- Who is it for?
- Adopt Stirrup if you want a small Python agent loop you intend to read and edit, and you are comfortable that the model decides the plan. Do not adopt it if you need a durable, resumable orchestration layer with retries and state persistence, since nothing in the README describes one.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 22 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
What Stirrup actually solves, and for whom
Most agent frameworks encode a workflow: a fixed sequence of plan, act, observe, reflect, with the framework deciding when each phase runs. Stirrup takes the opposite position. The README states that the project differs from other agent frameworks by working with the model rather than against it, letting the model choose its own approach to completing tasks, and it names Claude Code as the closest analogue. That is the whole thesis. The framework supplies the loop, the tool plumbing and the context handling, then stops making decisions.
The audience follows from that. This is for engineers who have already decided they want an agent that behaves like a coding assistant: one that receives a goal, picks its own tools, and terminates when it calls a finish tool. It is also explicitly a template. The README describes Stirrup as a lightweight framework, or starting point template, and offers a full customization path where you clone the repository and install it in editable mode. That framing matters. A team that wants a library to import and never touch is not the primary audience; a team that expects to fork and modify the loop is.
The agent loop, the session context manager and the Tool interface
The architecture visible in the README is four objects. Agent configures and runs the agent loop until a finish tool is called or max turns is reached. session() is an async context manager that sets up tools, manages files and handles cleanup, and it is what returns the run result. Tool is the definition surface, with parameters declared through Pydantic. ToolProvider manages tools that need a lifecycle, such as connections or temporary directories.
The data flow is worth stating plainly because it explains several design choices. You construct a client first, passing base_url, model, max_tokens and context_window_tokens. You construct an Agent from that client, optionally with an explicit tool list and a max_turns bound. You enter a session with an output_dir, and you call session.run() with a prompt string. What comes back is a three-part tuple: finish_params, history and metadata. finish_params is the payload the model supplied when it called the finish tool, which is how structured output leaves the loop. history is the conversation. metadata is described as covering tool lifecycle, logging and file outputs.
Two details in that flow are easy to miss. First, context_window_tokens is passed by the caller, not discovered from the provider, which means the framework trusts you to know the model's window. Second, if you pass no tools, the agent falls back to default_tools(), which the README lists as code execution plus web tools. That default is convenient for a demo and consequential for anything else, because it means an agent constructed with no arguments can run shell commands locally.
Getting it running: install extras, set two keys, pick a client
Installation is a plain PyPI package. The README gives pip install stirrup or uv add stirrup for the core, and a bracketed extras syntax for optional components: stirrup[all], and individually stirrup[litellm], stirrup[docker], stirrup[e2b], stirrup[mcp] and stirrup[browser]. Those extras map onto the feature list, so the Docker and E2B sandbox paths and the MCP client are opt-in rather than installed by default.
The quick start uses ChatCompletionsClient with base_url set to https://openrouter.ai/api/v1 and model set to anthropic/claude-opus-5, alongside max_tokens=8_192 and context_window_tokens=1_000_000. The README notes the client picks up OPENROUTER_API_KEY from the environment automatically. It also states that web search requires BRAVE_API_KEY, and that the agent still works without it but web search will be unavailable. That is a real deployment constraint: the default tool set is not fully functional with a single API key.
Provider switching is handled two ways. For OpenAI-compatible endpoints you change base_url and pass api_key explicitly, which the README demonstrates with https://api.deepseek.com and a DEEPSEEK_API_KEY environment variable. For Anthropic, Google and others you install the litellm extra and use LiteLLMClient with a model_slug, max_tokens and context_window_tokens, with model information coming from the client rather than the Agent. There is also a bring-your-own-client path, since the README lists creating your own client alongside the two shipped options.
Where the lightweight approach costs you
The README's central claim, that the framework gets out of the way, is also its main limitation. If the model chooses its own approach, then reproducibility is the model's problem, not the framework's. There is no described mechanism for constraining the agent to a fixed sequence of steps, no described retry policy, and no described persistence layer for a run that dies midway. The session context manager handles tool lifecycle and cleanup, which is a different concern from durability. Anyone who needs an agent that survives a process restart should assume they are building that layer themselves.
Context management is described as automatically summarizing conversation history when approaching context limits. The README does not state how that summarization is triggered, what is retained, whether it is configurable, or what happens to tool call and tool result pairs that get split across a summarization boundary. For a long-running agent that is exactly the code path you would want to read before trusting it. Treat the feature as present but unspecified in the public material.
The max_turns parameter is the other blunt instrument. It is the only described termination condition besides the finish tool, so an agent that fails to call finish simply stops at the bound and returns whatever it has. There is no described distinction in the return tuple between a clean finish and a turn-limit exit, which means your calling code needs to inspect finish_params and decide for itself.
Finally, the default tool set deserves scrutiny. An Agent constructed without an explicit tools argument gets code execution, and the README lists running code locally as the first option alongside Docker and E2B. Local execution as a default is a reasonable choice for a developer running their own prompts on their own machine. It is the wrong default for a service that accepts prompts from elsewhere, and the framework does not appear to make that distinction for you.
How it differs from LangGraph and the OpenAI Agents SDK
The useful comparison is with graph-based orchestration, LangGraph being the common example. In that model you declare nodes and edges, and control flow is expressed in the graph rather than in the model's choices. Stirrup has no graph. Control flow is a loop plus a finish tool, and the branching happens inside the model's reasoning. The practical difference shows up when something goes wrong: with a graph you can point at the edge that was taken and change it, whereas with Stirrup the corrective action is usually a change to the prompt, the tool descriptions, or the model.
The OpenAI Agents SDK sits closer to Stirrup in spirit, since it also centers a loop with tools and handoffs. The visible difference here is provider posture. Stirrup ships ChatCompletionsClient for OpenAI-compatible endpoints and LiteLLMClient for everything else, and treats the client as an injectable dependency you can replace. That makes it straightforward to point the same agent at OpenRouter, DeepSeek or an internal gateway by changing a base_url. The cost of that flexibility is that model metadata such as the context window is your responsibility to supply.
There is also a sibling implementation. The README notes that StirrupJS is the TypeScript implementation of the same project. If your stack is Python, that is a footnote. If you are a polyglot team trying to keep one agent design across a Python service and a Node front end, it is the reason to look at this repository rather than a Python-only alternative.
Maintenance, versioning and what the MIT licence does not cover
The release history shows v0.2.0 in August 2026, preceded by v0.1.12 and v0.1.11 in the two months before it. That is a rapid cadence on a pre-1.0 version line, which is the relevant maintenance fact: minor version bumps can carry breaking changes by convention, and the jump from 0.1.x to 0.2.0 is exactly the kind of release where you should read the notes before upgrading. The repository is not archived and the last push postdates the v0.2.0 tag, so the project is active in the literal sense. Pinning a version in your dependency file is the obvious mitigation, and it is worth doing before you build anything on top of the Tool interface.
The licence is MIT, which is permissive and short. The one thing to note is that MIT covers the framework code, not the services it talks to. Your agent will be calling a model provider, and possibly Brave for search and E2B for sandboxes, each under its own terms. The README's mention of analysing Claude Code, Codex and other leading agents to incorporate best practices is a description of how the defaults were chosen, not a claim about code provenance. If that distinction matters to your legal review, read the repository rather than the README.
On upgrade cost specifically: the extras structure means a dependency change can arrive as a new extra rather than a new core dependency, which keeps the base install small. The flip side is that the surface you depend on is spread across the core package and up to five optional extras, so a lockfile is more useful here than in a framework with a single install path.
The customization path is the real product
The README gives two ways to consume Stirrup, and they are not equivalent. The pip install path treats it as a package. The clone path, git clone followed by pip install -e . or uv venv and uv pip install -e '.[all]', treats it as a starting template you intend to edit, and the README points to a full customization guide for that route. Given that the framework's stated value is getting out of the way, the second path is where the project makes most sense. The parts you would most likely need to change are the ones the README leaves thinnest: the summarization trigger, the termination conditions, and the sandbox choice for code execution.
That is also the honest test of whether Stirrup fits. If reading and modifying the agent loop sounds like work you want to avoid, the framework's main selling point is not a benefit to you, and a more opinionated framework with a defined workflow will get you to a working agent faster. If it sounds like the point, then the small surface area is the feature: four objects, one async context manager, and a return tuple you can inspect.
Editorial conclusion
Adopt Stirrup if you want a small Python agent loop you intend to read and edit, and you are comfortable that the model decides the plan. Do not adopt it if you need a durable, resumable orchestration layer with retries and state persistence, since nothing in the README describes one. Before committing, verify three things in the repository itself: whether the default web tools require BRAVE_API_KEY in your deployment, which optional extras your sandbox path needs (docker or e2b), and whether the context summarization behaviour is configurable or fixed.
Community notes