Skip to main content

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 run as 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_CONTENT environment variable. This avoids the need for on-disk opencode.json files.
  • 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 opencode subprocess 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 --session flag.

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 with PY_VERSIONS="3.12 3.13").
  • CI: GitHub Actions runs tests on Python 3.10–3.14 using uv (E2E remains opt-in).

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

loopbot-0.0.0.dev0.tar.gz (94.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

loopbot-0.0.0.dev0-py3-none-any.whl (13.9 kB view details)

Uploaded Python 3

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

Hashes for loopbot-0.0.0.dev0.tar.gz
Algorithm Hash digest
SHA256 fd813b44755dd1747cdcd655f4f48a92be716c52240633bcd0583cdc676eb0bd
MD5 29552035c286b754927f33434d3213b4
BLAKE2b-256 ab58d66e12d122256b206decb9dabe03d1fb64a01e1a4e7e590d1b729612b127

See more details on using hashes here.

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

Hashes for loopbot-0.0.0.dev0-py3-none-any.whl
Algorithm Hash digest
SHA256 c3b9be23a769988485a88a4d2579d84ec5ab3bb30bebc9ea3c88dead30aacd01
MD5 81a356850c546ba24bbdf0be902349ac
BLAKE2b-256 1805c8bc04741ed56cddd9e5a483068f8bea2991c2b75063d126f2d73f2fc942

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page