Skip to main content

Qoder Agent SDK for Python

Python SDK for building applications on top of Qoder Agent.

The SDK starts qodercli for you, streams agent messages back to Python, and lets your application configure tools, permissions, working directories, MCP servers, hooks, and interactive sessions.

Installation

pip install qoder-agent-sdk

Prerequisites:

  • Python 3.10+
  • A Qoder account or another authentication method supported by your host application

CLI Behavior

Published platform wheels include a bundled qodercli, so a separate CLI installation is not required for normal SDK use. If you prefer to use a system-wide CLI or a pinned local build, pass QoderAgentOptions(cli_path=...).

Authentication

Every SDK query needs an explicit authentication option.

Authentication method Identity Use case
Personal Access Token (PAT) A Qoder user Automation that needs the user's permissions and data
Service Account An organization workload Services and jobs that should not depend on a personal account
Local qodercli session The signed-in user Interactive development on a workstation

For a PAT, generate a token at qoder.com/account/integrations, store it in a secret manager, and expose it through the default environment variable:

export QODER_PERSONAL_ACCESS_TOKEN=your-token
from qoder_agent_sdk import QoderAgentOptions, access_token_from_env

options = QoderAgentOptions(auth=access_token_from_env())

For a Service Account, read the key from your secret manager and pass it directly to the SDK:

from qoder_agent_sdk import QoderAgentOptions, service_account

# Get the Service Account key from the host's secret manager adapter.
service_account_key = read_secret("qoder-service-account-key")
options = QoderAgentOptions(
    auth=service_account(service_account_key=service_account_key)
)

The SDK and CLI obtain and refresh short-lived Service Account tokens for this authentication method. A host can retain the Service Account key and use service_account(fetch_service_account_token=...) to obtain and refresh short-lived SATs for qodercli. See the host callback example for a complete Token exchange and query. To reuse a signed-in developer workstation, use qodercli_auth(). See the SDK authentication guide for complete setup instructions and security guidance.

Quick Start

import anyio
from qoder_agent_sdk import QoderAgentOptions, qodercli_auth, query


async def main() -> None:
    options = QoderAgentOptions(auth=qodercli_auth())

    async for message in query(
        prompt="What is 2 + 2?",
        options=options,
    ):
        print(message)


anyio.run(main)

Basic Usage

query() runs a single SDK query and returns an async iterator of response messages.

from qoder_agent_sdk import (
    AssistantMessage,
    QoderAgentOptions,
    TextBlock,
    qodercli_auth,
    query,
)

options = QoderAgentOptions(
    auth=qodercli_auth(),
    system_prompt="You are a helpful assistant.",
    max_turns=1,
)

async for message in query(prompt="Explain this repository", options=options):
    if isinstance(message, AssistantMessage):
        for block in message.content:
            if isinstance(block, TextBlock):
                print(block.text)

Tools and Permissions

Qoder Agent can use tools such as file reads, file edits, shell commands, and MCP tools. allowed_tools is an approval allowlist: listed tools are auto-approved, while unlisted tools continue through permission_mode and can_use_tool for a decision. It does not remove tools from the agent's available toolset. To block tools, use disallowed_tools.

from qoder_agent_sdk import QoderAgentOptions, qodercli_auth, query

options = QoderAgentOptions(
    auth=qodercli_auth(),
    allowed_tools=["Read", "Edit"],
    disallowed_tools=["Bash"],
    permission_mode="acceptEdits",
)

async for message in query(
    prompt="Update the README introduction.",
    options=options,
):
    print(message)

For application-specific approval flows, provide can_use_tool:

from qoder_agent_sdk import (
    PermissionResultAllow,
    PermissionResultDeny,
    QoderAgentOptions,
    ToolPermissionContext,
    qodercli_auth,
)


async def can_use_tool(
    tool_name: str,
    tool_input: dict,
    context: ToolPermissionContext,
):
    if tool_name == "Bash":
        return PermissionResultDeny(message="Shell commands are disabled here.")
    return PermissionResultAllow()


options = QoderAgentOptions(
    auth=qodercli_auth(),
    can_use_tool=can_use_tool,
)

Working Directory

Use cwd to run the agent in a specific project directory:

from pathlib import Path

from qoder_agent_sdk import QoderAgentOptions, qodercli_auth

options = QoderAgentOptions(
    auth=qodercli_auth(),
    cwd=Path("/path/to/project"),
)

Interactive Sessions

Use QoderSDKClient when you need a long-lived, bidirectional session instead of a single query() call.

from qoder_agent_sdk import QoderAgentOptions, QoderSDKClient, qodercli_auth

options = QoderAgentOptions(auth=qodercli_auth())

async with QoderSDKClient(options=options) as client:
    await client.query("Inspect this project and summarize the main modules.")

    async for message in client.receive_response():
        print(message)

QoderSDKClient is useful for chat interfaces, follow-up prompts, interrupts, runtime permission changes, MCP server management, and other workflows that need state across multiple turns.

Use message priority to steer a turn that is already running:

await client.query(
    "Stop the current direction and inspect the failing tests first.",
    priority="now",
)

priority="now" stops the current response and handles the message immediately. priority="next" is the default and uses the next suitable point. priority="later" waits until the current response finishes. should_query=False adds the message to the conversation without starting a response by itself; its processing time still follows priority.

Assign a session-unique message_uuid to messages that need tracking or cancellation, and do not reuse UUIDs within a session. await client.interrupt() stops the current response and returns None. await client.cancel_async_message(message_uuid) returns True when the queued message is cancelled and False when it can no longer be cancelled.

External Session Storage

Use session_store when a host needs durable transcripts outside the local machine. The SDK mirrors entries after qodercli commits them locally. A later process can restore the same session before qodercli starts:

qodercli commit -> SDK append(key, entries) -> external store
external store -> SDK load(key) -> temporary QODER_CONFIG_DIR -> qodercli resume
from qoder_agent_sdk import (
    InMemorySessionStore,
    QoderAgentOptions,
    qodercli_auth,
    query,
)

session_store = InMemorySessionStore()

options = QoderAgentOptions(
    auth=qodercli_auth(),
    cwd="/path/to/project",
    session_store=session_store,
)

async for message in query(prompt="Inspect this project.", options=options):
    print(message)

resume_options = QoderAgentOptions(
    auth=qodercli_auth(),
    cwd="/path/to/project",
    resume="11111111-1111-4111-8111-111111111111",
    session_store=session_store,
)

Every store implements async append(key, entries) and load(key). Implement list_sessions(project_key) for continue_conversation=True and session listing, list_subkeys(key) to restore child-agent transcripts, and delete(key) for deletion. Entries are opaque JSON dictionaries and must remain in append order. A child transcript uses an opaque subpath such as subagents/agent-<id>; the key does not include the on-disk .jsonl extension.

When load() returns None or an empty list for an explicit resume, the SDK falls back to the same local session ID. Missing or empty child transcripts do not prevent restoration of the main session, and unsafe subpaths are ignored.

session_store_flush="batched" is the default. "eager" starts each append without waiting for the result boundary. Final append failures are emitted as non-fatal SDKMirrorErrorMessage values. load_timeout_ms defaults to 60,000 ms. Session storage cannot be combined with file checkpointing, a custom transport, or the Cloud Agent runtime. It requires the built-in subprocess transport.

The existing local session helpers remain synchronous. External stores use the async helpers list_sessions_from_store, get_session_info_from_store, get_session_messages_from_store, rename_session_via_store, tag_session_via_store, fork_session_via_store, and delete_session_via_store. Local and external child-agent transcripts are available through list_subagents / get_subagent_messages and list_subagents_from_store / get_subagent_messages_from_store. Use import_session_to_store to copy an existing local main transcript, child-agent transcripts, and metadata into a store.

Production stores

The SDK exports the SessionStore protocol but does not ship a production-ready external storage implementation. Implement the protocol against shared storage operated by your application, then validate its append/load ordering, project isolation, subkey handling, and deletion behavior with run_session_store_conformance.

Custom Tools

You can expose Python functions to Qoder Agent as in-process SDK MCP servers. This avoids managing a separate MCP subprocess for simple application-local tools.

from qoder_agent_sdk import (
    QoderAgentOptions,
    QoderSDKClient,
    create_sdk_mcp_server,
    qodercli_auth,
    tool,
)


@tool("greet", "Greet a user", {"name": str})
async def greet_user(args):
    return {
        "content": [
            {"type": "text", "text": f"Hello, {args['name']}!"}
        ]
    }


server = create_sdk_mcp_server(
    name="my-tools",
    version="1.0.0",
    tools=[greet_user],
)

options = QoderAgentOptions(
    auth=qodercli_auth(),
    mcp_servers={"tools": server},
    allowed_tools=["mcp__tools__greet"],
)

async with QoderSDKClient(options=options) as client:
    await client.query("Greet Alice.")
    async for message in client.receive_response():
        print(message)

Hooks

Hooks are deterministic Python callbacks invoked at specific points in the agent loop. They are useful for validation, policy checks, logging, and application-specific feedback.

from qoder_agent_sdk import HookMatcher, QoderAgentOptions, qodercli_auth


async def block_script(input_data, tool_use_id, context):
    if input_data["tool_name"] != "Bash":
        return {}

    command = input_data["tool_input"].get("command", "")
    if "./deploy.sh" in command:
        return {
            "hookSpecificOutput": {
                "hookEventName": "PreToolUse",
                "permissionDecision": "deny",
                "permissionDecisionReason": "Deployment scripts require review.",
            }
        }
    return {}


options = QoderAgentOptions(
    auth=qodercli_auth(),
    hooks={
        "PreToolUse": [
            HookMatcher(matcher="Bash", hooks=[block_script]),
        ],
    },
)

Error Handling

from qoder_agent_sdk import (
    CLIConnectionError,
    CLIJSONDecodeError,
    CLINotFoundError,
    ProcessError,
    QoderAgentOptions,
    QoderSDKError,
    qodercli_auth,
    query,
)

try:
    async for message in query(
        prompt="Hello Qoder",
        options=QoderAgentOptions(auth=qodercli_auth()),
    ):
        print(message)
except CLINotFoundError:
    print("qodercli was not found. Install a platform wheel or set cli_path.")
except CLIConnectionError as exc:
    print(f"Connection failed: {exc}")
except ProcessError as exc:
    print(f"qodercli exited with code {exc.exit_code}")
except CLIJSONDecodeError as exc:
    print(f"Could not parse qodercli output: {exc}")
except QoderSDKError as exc:
    print(f"SDK error: {exc}")

License and Terms

Copyright (c) 2026 Qoder

Use of this software is governed by the Qoder Product Service Terms:

https://qoder.com/product-service

By installing or using this package, you agree to those terms.

Download files

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

Source Distribution

qoder_agent_sdk-1.0.12.tar.gz (123.0 kB view details)

Uploaded Source

Built Distributions

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

qoder_agent_sdk-1.0.12-py3-none-win_amd64.whl (60.3 MB view details)

Uploaded Python 3Windows x86-64

qoder_agent_sdk-1.0.12-py3-none-musllinux_1_2_x86_64.whl (49.5 MB view details)

Uploaded Python 3musllinux: musl 1.2+ x86-64

qoder_agent_sdk-1.0.12-py3-none-musllinux_1_2_aarch64.whl (48.9 MB view details)

Uploaded Python 3musllinux: musl 1.2+ ARM64

qoder_agent_sdk-1.0.12-py3-none-manylinux_2_17_x86_64.whl (50.4 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ x86-64

qoder_agent_sdk-1.0.12-py3-none-manylinux_2_17_aarch64.whl (50.2 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ARM64

qoder_agent_sdk-1.0.12-py3-none-macosx_11_0_x86_64.whl (42.8 MB view details)

Uploaded Python 3macOS 11.0+ x86-64

qoder_agent_sdk-1.0.12-py3-none-macosx_11_0_arm64.whl (38.8 MB view details)

Uploaded Python 3macOS 11.0+ ARM64

File details

Details for the file qoder_agent_sdk-1.0.12.tar.gz.

File metadata

  • Download URL: qoder_agent_sdk-1.0.12.tar.gz
  • Upload date:
  • Size: 123.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.10.14

File hashes

Hashes for qoder_agent_sdk-1.0.12.tar.gz
Algorithm Hash digest
SHA256 c601145908008f8af0891069f776822fe95ea873cb5d6132449a933ed8db3c06
MD5 85018f79410ca5fa0ac42fd05fecf887
BLAKE2b-256 ef3464778b1205052c3d4eaca0fb87c2777f05ffdfab690613c1a7eb4e399fba

See more details on using hashes here.

File details

Details for the file qoder_agent_sdk-1.0.12-py3-none-win_amd64.whl.

File metadata

File hashes

Hashes for qoder_agent_sdk-1.0.12-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 149274ff92ea57d00ad0c3c250bd71f6f2e956bd583cc0369ffeb4143ee76116
MD5 5c89cf8e4d162f9da923c88e88ccfdb7
BLAKE2b-256 f338a4e18f9fb86cc7ee96bafa77365a5bfa4e74bb7212ffaff62846aba37827

See more details on using hashes here.

File details

Details for the file qoder_agent_sdk-1.0.12-py3-none-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for qoder_agent_sdk-1.0.12-py3-none-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 2fd12af55d213f07177f17b9dc8b48a61eec04610bd5ee4cb41d910fc0bdc910
MD5 8fffe5dfe71884feb78c706d1ddf6f6d
BLAKE2b-256 f2f0d6375c964cbdc197dba9ffec9ac39c2902e7fcddefef18d00f8435a90c9d

See more details on using hashes here.

File details

Details for the file qoder_agent_sdk-1.0.12-py3-none-musllinux_1_2_aarch64.whl.

File metadata

File hashes

Hashes for qoder_agent_sdk-1.0.12-py3-none-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 58c989c45d5be0c205f8d8a8bd38ba659a51580332008c753f6cade18e17d06a
MD5 38b76ede2d2c7d744fe1938c82d3ea73
BLAKE2b-256 826ca305956796b29cf8f7276d3b4c235d16e54dcbc2b884870fbf8d4c7a0985

See more details on using hashes here.

File details

Details for the file qoder_agent_sdk-1.0.12-py3-none-manylinux_2_17_x86_64.whl.

File metadata

File hashes

Hashes for qoder_agent_sdk-1.0.12-py3-none-manylinux_2_17_x86_64.whl
Algorithm Hash digest
SHA256 849bfffb60e073eb2b65f8b8f746ebc8568a47f8739f8dbf56c78558b12592d7
MD5 362b9cc378b398bf122c2a3ea6c3cc2b
BLAKE2b-256 f9b2a7fe4af042ba11b0994e40aac12defe78f51429041b6d81a7bd92e457868

See more details on using hashes here.

File details

Details for the file qoder_agent_sdk-1.0.12-py3-none-manylinux_2_17_aarch64.whl.

File metadata

File hashes

Hashes for qoder_agent_sdk-1.0.12-py3-none-manylinux_2_17_aarch64.whl
Algorithm Hash digest
SHA256 4988a34c51a8903f26c4c753e1ac321fae5f1652b7131d1ad0817802eeec4bc2
MD5 ab87b4a3d0e09e82aa18b796a3ceb18e
BLAKE2b-256 3a15a5451232b31073121a9faea0af385d531a0021023f7916e0cac03cffc832

See more details on using hashes here.

File details

Details for the file qoder_agent_sdk-1.0.12-py3-none-macosx_11_0_x86_64.whl.

File metadata

File hashes

Hashes for qoder_agent_sdk-1.0.12-py3-none-macosx_11_0_x86_64.whl
Algorithm Hash digest
SHA256 985527b9e606697fcc96d98749b05104c62225e28ad5efa5182eb7aa6d2ec173
MD5 f0fd3a3193cd3eaff4e5f4d4726e6989
BLAKE2b-256 494f725cda18665314dabcc6fe59341ec8be993399a8d0f3fa4edd54841fbb03

See more details on using hashes here.

File details

Details for the file qoder_agent_sdk-1.0.12-py3-none-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for qoder_agent_sdk-1.0.12-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 c3ca3c32da734ba6a095fc09a283470e3be0b8e6bfbbb2675a5410f5124ac332
MD5 952fba4ae2c79e25bbdafe3c469aab78
BLAKE2b-256 fb6d398f2a026476a2bc9e9a950231767fe76e18c4463111f3d6085d2657dcbf

See more details on using hashes here.

Release history Release notifications | RSS feed

1.0.13

8 files

This release

1.0.12 This release

8 files

1.0.11

8 files

1.0.10

8 files

1.0.9

8 files

1.0.8

8 files

1.0.5

8 files

1.0.2

8 files

1.0.1

8 files

1.0.0

8 files

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