Skip to main content

swebot-client

Python client for the swebot autonomous coding agent.

Pure Python — zero dependencies beyond the standard library.

Install

# pip
pip install swebot-client

# uv
uv add swebot-client

Quick start

import swebot

print(swebot.ask("explain goroutines"))

That is the whole ceremony for a one-shot question against a backend on localhost. Stream it instead, when you want to watch it arrive:

for token in swebot.stream("explain goroutines"):
    print(token, end="", flush=True)

Take a session when the second question depends on the first — a session IS the context that makes a follow-up a follow-up:

with swebot.session(agent="developer") as s:
    s.send("read parser.go")
    print(s.send("what would you change about it?"))

Elsewhere, or behind a token:

swebot.connect("http://10.0.0.5:8080", token="…")   # or set SWEBOT_TOKEN

And the full client is one call away — everything below is reachable from it:

client = swebot.Client(timeout=30)
client.set_mode("autonomous")
session = client.create_session(agent="developer")

The same library under two names

import swebot is the front door; swebot_client is the same objects under the name existing scripts already import. They can be mixed in one program — swebot.TurnFailed is swebot_client.TurnFailed, not a copy of it — so nothing has to be rewritten to use the shorter form, and an except clause keeps catching either way.

from swebot_client import SwebotClient     # unchanged, and staying

Features

  • Streaming — real-time token-by-token output via SSE
  • Tool callbacks — observe tool invocations and results
  • Session management — create, resume, list, delete sessions
  • Mode / model control — switch modes, models, thinking, reasoning
  • Todos & checkpoints — read, create, update, delete todos; list/restore checkpoints
  • MCP management — configure MCP servers programmatically
  • Plugin management — install, remove, enable, disable plugins
  • AgentSpeak — multi-agent collaboration (join, leave, send messages)
  • Context control — compact or clear session context
  • Skills — list built-in skill agents

Examples

from swebot_client import SwebotClient, ToolCall

client = SwebotClient("http://localhost:8080")
client.wait_until_ready(timeout=10)

# Set mode to autonomous so the agent executes (not plans)
client.set_mode("autonomous")

# Enable extended thinking
client.set_thinking("high")

# Switch model
client.set_model("claude-opus-4-5")

# Create a session and send a message
session = client.create_session(agent="developer")

def on_tool(tc: ToolCall):
    print(f"  ⚙ {tc.name}")

reply = session.send_with_events(
    "create a hello.py file",
    on_tool_start=on_tool,
)

# Read todos
for todo in session.get_todos():
    print(f"[{todo.status}] {todo.title}")

# Token usage
usage = session.token_usage()
print(f"Tokens: {usage['tokens_in']:,} in / {usage['tokens_out']:,} out ({usage['usage_pct']}%)")

Pipeline example

from swebot_client import SwebotClient

client = SwebotClient()
client.wait_until_ready()
client.set_mode("autonomous")

# Stage 1: generate
s1 = client.create_session()
code = s1.send("Write a Python prime sieve for 0-1000000")

# Stage 2: review
s2 = client.create_session("code_auditor")
review = s2.send(f"Review this code:\n{code}")
print(review)

API reference

Module-level calls

Call Description
swebot.ask(message, agent="default", keep=False) One question in a session of its own → str
swebot.stream(message, agent="default", keep=False) The same, token by token → Iterator[str]
swebot.session(agent="default", keep=True) A session, as a context manager. Kept by default — pass keep=False for a scratch one
swebot.connect(addr, token, …) Point those three at a different backend → the Client
swebot.client() The client they are using

A backend that is not running gives a ConnectionError naming the address and telling you to start one, rather than a bare URLError from urllib.

The session ask and stream create is scratch: you never see its id, nothing can resume it, and a script asking a thousand questions would leave a thousand sessions behind. It is discarded when the answer is in — unless the session is still doing something, in which case it is left alone:

  • a wake-up is scheduled — the turn asked to be resumed, and the session is how it comes back. (The same rule swebot's own one-shot CLI applies.)
  • the turn is still running — an autonomous or goal continuation outlives the stream that started it, so a one-shot that set one going leaves it working rather than deleting it mid-turn.
  • anything unknown — an older backend that does not report wake-ups, a request that fails. Deleting is the direction that cannot be undone.

The backend checks again as it deletes, so a wake-up scheduled by another backend between the check and the delete cannot be lost. keep=True holds on to the session regardless; swebot.session() is for when the conversation itself matters.

SwebotClient(addr="http://localhost:8080", token="", timeout=60.0, stream_timeout=None)

No token needed for a backend on your own machine. If it was started with --token (which a backend bound off loopback requires), set SWEBOT_TOKEN in your environment — the SDK reads it automatically.

timeout bounds ordinary requests, so a backend that accepts the connection and then stops answering cannot hang your script; wait_until_ready(timeout=…) passes its remaining time down to each probe. stream_timeout is separate and defaults to no deadline, because a turn streams for as long as it runs and a silent tool call of several minutes is normal.

Errors

A turn that fails — the provider erroring, a stall, a cancellation — raises TurnFailed from send(), stream() and send_with_events(). Whatever text arrived before the failure is on the exception as .partial:

from swebot_client import TurnFailed

try:
    answer = session.send("refactor the parser")
except TurnFailed as e:
    print("the turn failed:", e)
    print("partial output was:", e.partial)

These used to return the empty string, or the partial text, with nothing to distinguish a failed turn from a short answer.

ToolCall

What the agent did, as on_tool_start / on_tool_result see it: id, name, input, output, and two flags that are NOT the same question.

Field Means
is_error the call did not succeed
not_run there was no call — declined, blocked in plan mode, refused by a plugin, cancelled before it started

A refused tool is not a failed tool, and anything auditing what the agent actually did needs to tell them apart. examples/17_failures.py shows all three outcomes.

Sessions

Method Description
create_session(agent) Create a new session → Session
get_session(id) Resume an existing session → Session
list_sessions() List all sessions
delete_session(id) Delete a session

Agents / Providers / Models

Method Description
list_agents() List available agents
get_agent(name) Get agent details (name, system_prompt, tools)
list_providers() List LLM providers
list_models(provider) List models for a provider → {provider, active, models}
set_model(model, provider) Switch model (and optionally provider)

Mode / Thinking / Reasoning

Method Description
get_mode() Current mode (plan, agent, autonomous)
set_mode(mode) Set mode: "plan", "agent", "autonomous"
get_thinking() Current thinking level
set_thinking(level) Set thinking: "", "low", "medium", "high"
get_reasoning() Current reasoning depth
set_reasoning(level) Set reasoning: "low", "medium", "high"

MCP Servers

Method Description
list_mcp() List MCP servers with connection state
add_mcp(name, ...) Add a new MCP server
update_mcp(name, ...) Update an existing server
delete_mcp(name) Remove a server
enable_mcp(name) Enable a disabled server
disable_mcp(name) Disable without removing
reload_mcp() Reconnect all enabled servers

Plugins

Method Description
list_plugins() List installed plugins
install_plugin(url) Install from GitHub (owner/repo)
remove_plugin(name) Uninstall a plugin
enable_plugin(name) Re-enable a disabled plugin
disable_plugin(name) Disable without removing

AgentSpeak (Multi-Agent)

Method Description
agentspeak_status() Connection status → {connected, project, role, url}
agentspeak_projects() List visible projects
agentspeak_who() List agents in current project
agentspeak_messages(since) Fetch recent messages
agentspeak_join(url, project, role) Connect and join a project
agentspeak_leave() Disconnect from project
agentspeak_send(message, to) Send message (broadcast or targeted)

Backend Management

Method Description
health() Check if backend is reachable
wait_until_ready(timeout) Block until backend responds
stats() Backend stats (model, tokens, uptime)
version() Version info (version, commit, latest)
skills() List built-in skill agents
panic() Emergency stop — cancel all; the mode stays as it is
shutdown() Gracefully stop the backend

Session

Messaging

Method Description
stream(message) Stream tokens → Iterator[str]
send(message) Send and get full reply → str
send_with_events(msg, on_token, on_tool_start, on_tool_result) Send with callbacks → str

Todos

Method Description
get_todos() List todo items → list[TodoItem]
create_todo(title) Create a new todo
update_todo(id, status) Update status: pending, in_progress, done
delete_todo(id) Delete a todo

Checkpoints

Method Description
list_checkpoints() List file checkpoints → list[dict]
restore_checkpoint(id) Restore a file to a previous checkpoint

Context

Method Description
compact() Trigger context compaction
clear() Clear all session context
token_usage() THIS session's usage → {tokens_in, tokens_out, context_window, usage_pct} — falls when the session is compacted
backend_token_totals() The backend's cumulative counters across every session

Info

Method Description
refresh() Reload session data from backend
message_count Number of messages (property)

Publishing to PyPI

cd sdk/python
python3 -m build
UV_PUBLISH_TOKEN=pypi-YOUR-TOKEN uv publish dist/*

Requirements

  • Python 3.9+
  • A running swebot backend (swebot --serve)

License

MIT

Code review

Review what a session changed, then choose what to fix. Findings are verified by an adversarial second pass — only confirmed ones can be applied.

from swebot_client import SwebotClient

session = SwebotClient().create_session()
session.send("Add a ParseInt helper to util/parse.go")

rev = session.review(mode="informative")   # or "autonomous"
if rev.running:
    rev = session.wait_for_review(rev.id)

for f in rev.findings:
    print(f.id, f.severity, f.file, f.claim, "confirmed" if f.confirmed else "refuted")

keep = [f.id for f in rev.confirmed if f.blocking]
drop = [f.id for f in rev.confirmed if not f.blocking]
if keep:
    session.apply_review(rev.id, keep)
if drop:
    session.dismiss_findings(rev.id, drop, reason="not now")

A session that changed no files returns scope="out_of_scope" (or "nothing_to_review") without calling a model at all.

Metadata

Release files for swebot-client 0.13.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for swebot-client 0.13.1
File Size Uploaded Provenance Actions
swebot_client-0.13.1.tar.gz 42.9 kB Without provenance Details for swebot_client-0.13.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for swebot-client 0.13.1
File Interpreter ABI Platform Actions
swebot_client-0.13.1-py3-none-any.whl Python 3 none any Details for swebot_client-0.13.1-py3-none-any.whl

Total release size: 64.6 kB

Release files / swebot_client-0.13.1.tar.gz

Download URL swebot_client-0.13.1.tar.gz
Size 42.9 kB
Tags Source
SHA-256 checksum
How to use checksums
b84651bbd3ae021f4d984e091ea627674bdc33e5730010b44ed03dc84e8c879f
BLAKE2b-256 checksum
How to use checksums
47f142074336a7170d2a25fec38ed6b393f843df3d073e65b13f0df05748cdc2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.13 {"installer":{"name":"uv","version":"0.12.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / swebot_client-0.13.1-py3-none-any.whl

Download URL swebot_client-0.13.1-py3-none-any.whl
Size 21.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
9fb5010f777c25bc1f7c02194a86dcd7d611c44e8aac9851031d02f790bedfdf
BLAKE2b-256 checksum
How to use checksums
254ead5327a55251fb6ddfd43fc2fdbbb0445ed7d2f02931010c01274cad15d5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.13 {"installer":{"name":"uv","version":"0.12.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Security for swebot-client 0.13.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page