Python SDK wrapper for the OpenCode AI coding agent.
Project description
LoopBot
Python SDK for invoking the OpenCode coding agent CLI in a headless, non-interactive manner.
Supports:
- Synchronous and Asynchronous modes
- Structured outputs using Pydantic models
- Sessions for multiple invocations with shared context
- Permission configuration for reading, writing, web, and bash tools
- Configurable working directory per agent, session, or call
Installation
You can install loopbot using uv (recommended) or pip.
# Using uv
uv pip install loopbot
# Using pip
pip install loopbot
Usage
Here are a few ways to use the loopbot SDK, from simple invocations to stateful, asynchronous sessions.
1. Basic Synchronous Agent
This is the simplest way to get a response from an agent. Permissions are configured to prevent the agent from performing any actions on your system.
from loopbot import Agent, Permission
# Configure a restrictive agent that cannot execute bash commands
agent = Agent(
model="anthropic/claude-sonnet-4-5",
permission=Permission(
webfetch=Permission.ALLOW,
)
)
# Invoke the agent with a prompt
response = agent.invoke("Do web search for 'opencode.ai zen models' and list them")
print(response.output)
## OpenCode Zen Models
- **GPT 5** (`gpt-5`)
- **GPT 5 Codex** (`gpt-5-codex`)
- **Claude Sonnet 4.5** (`claude-sonnet-4-5`)
- **Claude Sonnet 4** (`claude-sonnet-4`)
- **Claude Haiku 4.5** (`claude-haiku-4-5`)
- **Claude Haiku 3.5** (`claude-3-5-haiku`)
- **Claude Opus 4.1** (`claude-opus-4-1`)
- **Qwen3 Coder 480B** (`qwen3-coder`)
- **Grok Code Fast 1** (`grok-code`) - Currently free
- **Kimi K2** (`kimi-k2`)
- **Code Supernova** - Currently free (stealth model)
2. Structured Outputs with Pydantic
Get clean, validated data back from the agent by providing a Pydantic model. The agent will automatically format its response to fit the schema.
from loopbot import Agent, Permission
from pydantic import BaseModel, Field
class UserProfile(BaseModel):
name: str = Field(description="The user's full name.")
age: int = Field(description="The user's age in years.")
# Allow the agent to use web search but not file system or bash access
agent = Agent(
model="anthropic/claude-haiku-4-5",
permission=Permission(
bash=Permission.DENY,
edit=Permission.DENY,
webfetch=Permission.ALLOW,
)
)
# The agent will return a populated UserProfile instance
response = agent.invoke_structured(
"Extract the user's information: My name is Jane Doe and I am 28 years old.",
model_cls=UserProfile
)
user = response.output
print(f"Name: {user.name}, Age: {user.age}")
# > Name: Jane Doe, Age: 28
3. Stateful Sessions
Use a session to have a conversation where the agent remembers previous interactions. The session manager automatically handles passing the session ID between calls.
from loopbot import Agent, Permission
agent = Agent(
model="anthropic/claude-haiku-4-5",
permission=Permission(bash=Permission.DENY)
)
with agent.session() as s:
# First turn: The agent remembers the word "avocado"
s.invoke("Please remember this word for me: avocado")
# Second turn: The agent recalls the word from the session context
response = s.invoke("What was the word I asked you to remember?")
print(response.output)
# > The word you asked me to remember was "avocado".
4. Asynchronous Usage
For non-blocking applications, loopbot provides an async-native AsyncAgent and AsyncSession.
import asyncio
from loopbot import AsyncAgent, Permission
async def main():
agent = AsyncAgent(
model="anthropic/claude-haiku-4-5",
permission=Permission(bash=Permission.DENY)
)
async with agent.session() as s:
await s.invoke("Remember this number: 42")
response = await s.invoke("What was the number?")
print(response.output)
asyncio.run(main())
5. Working Directory (CWD)
The opencode subprocess runs in a chosen CWD. You can set it:
- Per agent (default):
Agent(..., workdir="/path/to/project") - Per session:
agent.session(workdir="/path/to/project") - Per call:
agent.invoke("...", workdir="/path/to/project")
Example with session-scoped CWD:
from loopbot import Agent, Permission
agent = Agent(model="anthropic/claude-haiku-4-5", permission=Permission(bash=Permission.ALLOW))
with agent.session(workdir="/tmp/projectA") as s:
r = s.invoke("Use the bash tool to run: ls -1")
print(r.output)
How It Works
loopbot is a lightweight wrapper that orchestrates calls to the opencode command-line tool. Understanding its mechanism can help you use it more effectively.
- Headless CLI Invocation: The SDK executes
opencode runas a subprocess in a non-interactive, JSON-streaming mode. It does not require the TUI. - Dynamic Configuration: Agent settings, such as the model and permissions, are passed to the CLI on-the-fly using the
OPENCODE_CONFIG_CONTENTenvironment variable. This avoids the need for on-diskopencode.jsonfiles. - Event Streaming: The CLI streams a series of JSON objects representing events (
step_start,text,tool_use,step_finish). The SDK parses these events into typed Python objects. - Working Directory: The
opencodesubprocess runs in a configured CWD (per agent/session/call). If unspecified, it inherits the current process CWD. - Session Management: Session IDs are extracted from the event stream and automatically passed back to the CLI in subsequent calls using the
--sessionflag.
For more information on the underlying agent, check out the official OpenCode Documentation.
Testing & CI
- Local:
make check(format, lint, type-check),make test(unit tests; E2E skipped),make coverage. - Multi-version:
make test-all-versions(uses uv; override withPY_VERSIONS="3.12 3.13"). - CI: GitHub Actions runs tests on Python 3.10–3.14 using uv (E2E remains opt-in).
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file loopbot-0.0.0.dev0.tar.gz.
File metadata
- Download URL: loopbot-0.0.0.dev0.tar.gz
- Upload date:
- Size: 94.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fd813b44755dd1747cdcd655f4f48a92be716c52240633bcd0583cdc676eb0bd
|
|
| MD5 |
29552035c286b754927f33434d3213b4
|
|
| BLAKE2b-256 |
ab58d66e12d122256b206decb9dabe03d1fb64a01e1a4e7e590d1b729612b127
|
File details
Details for the file loopbot-0.0.0.dev0-py3-none-any.whl.
File metadata
- Download URL: loopbot-0.0.0.dev0-py3-none-any.whl
- Upload date:
- Size: 13.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c3b9be23a769988485a88a4d2579d84ec5ab3bb30bebc9ea3c88dead30aacd01
|
|
| MD5 |
81a356850c546ba24bbdf0be902349ac
|
|
| BLAKE2b-256 |
1805c8bc04741ed56cddd9e5a483068f8bea2991c2b75063d126f2d73f2fc942
|