Documentation Index
Fetch the complete documentation index at: https://mintlify.com/swe-agent/mini-swe-agent/llms.txt
Use this file to discover all available pages before exploring further.
mini-swe-agent is built from three loosely coupled components — an agent, an environment, and a model — assembled together in a thin run script. Each component is a plain Python class, and the interfaces between them are protocols (duck typing), not deep inheritance hierarchies. This means you can swap in a custom subclass or a completely new implementation at any layer without touching the others.
Keep your changes as minimal as possible. Override a single method, call super() for everything else, and you’ll have a maintainable extension that automatically picks up future improvements to the base classes.
The component model
To build a custom version of mini-swe-agent:
Pick an agent class
The agent class controls the main loop and how the model’s responses are processed.| Class | Description |
|---|
DefaultAgent | Autonomous loop — the simplest option |
InteractiveAgent | Adds human-in-the-loop confirmation and mode switching |
Pick an environment class
The environment class decides where and how bash commands are executed.| Class | Description |
|---|
LocalEnvironment | Runs commands on the host via subprocess.run |
DockerEnvironment | Runs commands inside a Docker container |
Pick a model class
The model class handles querying the LM, parsing actions from responses, and formatting observations.| Class | Description |
|---|
LitellmModel | Tool-calling via LiteLLM (default) |
LitellmTextbasedModel | Regex-based text parsing via LiteLLM |
Use get_model(input_model_name=...) for automatic class selection. Write a run script
A run script instantiates your chosen classes and calls agent.run(task). See the hello world run script for a minimal example.from minisweagent.agents.default import DefaultAgent
from minisweagent.models import get_model
from minisweagent.environments.local import LocalEnvironment
agent = DefaultAgent(
get_model(input_model_name="anthropic/claude-sonnet-4-5-20250929"),
LocalEnvironment(),
)
result = agent.run(task)
Customization recipes
Custom action handling with Python functions
You can intercept specific commands and handle them in Python instead of passing them to the shell. This works from either the agent or the environment side.
Subclass the agent
Subclass the environment
Override execute_actions to intercept matching commands before falling back to super().from minisweagent.agents.default import DefaultAgent
import shlex
def python_function(*args) -> dict:
# your custom logic here
return {"output": "..."}
class AgentWithPythonFunctions(DefaultAgent):
def execute_actions(self, message: dict) -> list[dict]:
for action in message.get("extra", {}).get("actions", []):
command = action.get("command", "")
if command.startswith("python_function"):
args = shlex.split(command.removeprefix("python_function").strip())
return self.add_messages(self.model.format_observation_messages(
message, [python_function(*args)], self.get_template_vars()
))
return super().execute_actions(message)
Override execute so the interception is transparent to the agent.from minisweagent.agents.default import DefaultAgent
from minisweagent.environments.local import LocalEnvironment
from minisweagent.models.litellm_model import LitellmModel
import shlex
def python_function(*args) -> dict:
# your custom logic here
return {"output": "..."}
class EnvironmentWithPythonFunctions(LocalEnvironment):
def execute(self, action: dict, cwd: str = "") -> dict:
command = action.get("command", "")
if command.startswith("python_function"):
args = shlex.split(command.removeprefix("python_function").strip())
return python_function(*args)
return super().execute(action, cwd)
agent = DefaultAgent(
LitellmModel(model_name="gpt-4o"),
EnvironmentWithPythonFunctions(),
)
Action validation — blocking forbidden patterns
Use a custom config class to make the forbidden patterns configurable, then validate every command before execution.
Subclass the agent
Subclass the environment
import re
from minisweagent.agents.default import DefaultAgent, AgentConfig
from minisweagent.exceptions import FormatError
class ValidatingAgentConfig(AgentConfig):
forbidden_patterns: list[str] = [
r"rm -rf /",
r"sudo.*passwd",
r"mkfs\.",
]
class ValidatingAgent(DefaultAgent):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs, config_class=ValidatingAgentConfig)
def execute_actions(self, message: dict) -> list[dict]:
for action in message.get("extra", {}).get("actions", []):
command = action.get("command", "")
for pattern in self.config.forbidden_patterns:
if re.search(pattern, command, re.IGNORECASE):
raise FormatError(self.model.format_message(
role="user",
content="Action blocked: forbidden pattern detected",
))
return super().execute_actions(message)
Environment-side validation returns a soft error dict rather than raising an exception, so the agent can continue.import re
from minisweagent.agents.default import DefaultAgent
from minisweagent.environments.local import LocalEnvironment, LocalEnvironmentConfig
from minisweagent.models.litellm_model import LitellmModel
class EnvironmentWithForbiddenPatternsConfig(LocalEnvironmentConfig):
forbidden_patterns: list[str] = [
r"rm -rf /",
r"sudo.*passwd",
r"mkfs\.",
]
class EnvironmentWithForbiddenPatterns(LocalEnvironment):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs, config_class=EnvironmentWithForbiddenPatternsConfig)
def execute(self, action: dict, cwd: str = "") -> dict:
command = action.get("command", "")
for pattern in self.config.forbidden_patterns:
if re.search(pattern, command, re.IGNORECASE):
return {"output": "Action blocked: forbidden pattern detected", "returncode": 1}
return super().execute(action, cwd)
agent = DefaultAgent(
LitellmModel(model_name="gpt-4o"),
EnvironmentWithForbiddenPatterns(),
)
Agent that exits on a submit command
Raise the Submitted exception from execute_actions or execute to end the run immediately when the agent issues a submit command.
Subclass the agent
Subclass the environment
from minisweagent.agents.default import DefaultAgent
from minisweagent.exceptions import Submitted
class AgentQuitsOnSubmit(DefaultAgent):
def execute_actions(self, message: dict) -> list[dict]:
for action in message.get("extra", {}).get("actions", []):
if action.get("command", "") == "submit":
raise Submitted({
"role": "exit",
"content": "The agent has finished its task.",
"extra": {"exit_status": "Submitted", "submission": ""},
})
return super().execute_actions(message)
from minisweagent.agents.default import DefaultAgent
from minisweagent.environments.local import LocalEnvironment
from minisweagent.models.litellm_model import LitellmModel
from minisweagent.exceptions import Submitted
class EnvironmentQuitsOnSubmit(LocalEnvironment):
def execute(self, action: dict, cwd: str = "") -> dict:
if action.get("command", "") == "submit":
raise Submitted({
"role": "exit",
"content": "The agent has finished its task.",
"extra": {"exit_status": "Submitted", "submission": ""},
})
return super().execute(action, cwd)
agent = DefaultAgent(
LitellmModel(model_name="gpt-4o"),
EnvironmentQuitsOnSubmit(),
)
Overriding the default entry point
When you run the mini CLI, it calls the default run script. You can replace that script with your own by setting the MSWEA_DEFAULT_RUN environment variable to the dotted import path of your run script’s main function:
export MSWEA_DEFAULT_RUN=mypackage.mymodule.main
mini -t "Fix the bug in app.py"
This lets you distribute a drop-in replacement for mini without forking the package.
Running mini-swe-agent at scale with Ray
For massively parallel agent runs (e.g., large-scale SWE-bench evaluations), mini-swe-agent can be parallelized with Ray. The Anyscale blog post on massively parallel agentic simulations walks through the approach in detail.