mini-swe-agent is built around a deliberately simple, stateless design. Rather than maintaining a persistent shell session, every action is an independentDocumentation 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.
subprocess.run call. The message list is the entire trajectory — there is no separate state object. Each iteration appends to that list and nothing else, which makes the agent easy to reason about, extend, and debug.
The main loop
DefaultAgent.run initializes the message history with a system message and a user message rendered from Jinja2 templates, then calls step() in a loop until a message with role="exit" appears at the end of the list.
Initialize messages
run() renders the system_template and instance_template configs using Jinja2 and adds both messages to the (initially empty) self.messages list. The task description and any extra keyword arguments are available as template variables.Agent.step()
Each iteration calls It sequences two operations: first query the language model, then execute whatever actions the model requested.
step(), which is a single line:Agent.query()
query() checks cost and step limits before calling Model.query(self.messages). The returned message is appended to the history via add_messages() and also returned to the caller. Cost is accumulated from message["extra"]["cost"].Agent.execute_actions()
execute_actions() iterates over every action embedded in the model message, calls Environment.execute() for each one, then formats the results into observation messages via Model.format_observation_messages(). The observations are appended to the history.Actions and the code block format
The model signals a bash command by wrapping it in a fenced code block with the language tagmswea_bash_command:
action_regex config option controls exactly which pattern is extracted. When using the default tool-calling model class, the model invokes a native “bash” tool and the actions are extracted from the tool-call payload instead.
Flow control via exceptions
Error conditions and the finish condition are both signalled by raising exceptions that inherit fromInterruptAgentFlow (defined in minisweagent.exceptions). Every exception in the hierarchy carries one or more messages that get appended to the trajectory before the loop checks whether to stop.
| Exception | Trigger |
|---|---|
Submitted | Environment output starts with COMPLETE_TASK_AND_SUBMIT_FINAL_OUTPUT |
LimitsExceeded | step_limit or cost_limit exceeded |
TimeExceeded | wall_time_limit_seconds exceeded |
FormatError | Model output is not in the expected format |
UserInterruption | User cancels the run |
InterruptAgentFlow) are caught by a separate except Exception branch, which adds an exit message and then re-raises, so the caller still sees the error.
Because every action is an independent
subprocess.run call there is no shell session to corrupt. Problems like “when has the command finished?”, “what if the command kills the shell?”, and “what if interrupt signals pollute subsequent output?” simply do not arise. The trade-off is that directory changes and exported environment variables do not persist across actions — but prefixing cd /path/to/project && to each command (which many models do automatically) is all that is needed.Key method reference
| Method | Location | Description |
|---|---|---|
DefaultAgent.run() | agents/default.py:85 | Initializes messages and drives the step loop |
DefaultAgent.step() | agents/default.py:107 | One iteration: query() then execute_actions() |
DefaultAgent.query() | agents/default.py:111 | Checks limits, calls Model.query, accumulates cost |
DefaultAgent.execute_actions() | agents/default.py:135 | Runs each action, formats and appends observations |
DefaultAgent.add_messages() | agents/default.py:66 | Appends messages to self.messages and returns them |