Skip to main content

Qoder Agent SDK for Python

Python SDK for building applications on top of Qoder Agent.

The SDK starts qodercn 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 qodercn-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 qodercn, 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 qodercn session The signed-in user Interactive development on a workstation

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

export QODERCN_PERSONAL_ACCESS_TOKEN=your-token
from qodercn_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 qodercn_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 qodercn. 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 qodercn_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 qodercn_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)

Code Security

Built-in code security is disabled by default in SDK sessions. Enable only the capabilities the integration needs:

options = QoderAgentOptions(
    auth=qodercli_auth(),
    cwd="/path/to/project",
    security_scan={
        "l1_static_check": True,
        "l2_lightweight_scan": True,
        "l3_deep_scan": False,
    },
)

Omitted switches remain disabled. The top-level option is authoritative for the SDK session. Enabling any switch also makes the native security skill available; project and file scans do not have a separate switch.

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 qodercn_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 qodercn_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,
)

Plan Mode

Plan Mode is independent from tool permissions. Set its initial state with plan_mode; the SDK applies it after the CLI handshake and before the first user message, while preserving the underlying permission_mode:

options = QoderAgentOptions(
    auth=qodercli_auth(),
    permission_mode="default",
    plan_mode=True,
)

For a live session, use await client.set_plan_mode(True | False) to switch the state and await client.get_plan_mode() to read the authoritative current state. These APIs require a CLI that advertises the plan_mode_v1 capability.

For compatibility with existing consumers, SystemMessage init data projects permissionMode as "plan" while Plan Mode is active. This does not replace the underlying tool permission mode; after leaving Plan Mode, the field reports that mode again. Use the Plan APIs and PlanModeChangedMessage as the authoritative Plan state.

Working Directory

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

from pathlib import Path

from qodercn_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 qodercn_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 qodercn commits them locally. A later process can restore the same session before qodercn starts:

qodercn commit -> SDK append(key, entries) -> external store
external store -> SDK load(key) -> temporary QODERCN_CONFIG_DIR -> qodercn resume
from qodercn_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. 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.

Session message readers default to view="runtime", which returns the latest Compact Summary and messages written after it. Pass view="historical" to get_session_messages or get_session_messages_from_store to read the real active lineage across Compact boundaries; Compact Boundary and Summary records are hidden from that projection. The local and external fork_session helpers use the same historical lineage, so up_to_message_id may target a message before Compact.

For a running local session, QoderSDKClient.rewind() previews or executes a conversation, files, or both rewind when the bundled CLI advertises session_rewind_v1. To start a new process from a persisted historical node, set QoderAgentOptions.resume, resume_session_at, and optionally resume_drops_turn; combine them with fork_session=True to preserve the source session.

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.

Memory

Configure native or custom memory with QoderAgentOptions(memory=...). Interactive clients expose flush_memory() and refresh_memory(). See Memory for configuration, generation callbacks, and lifecycle behavior.

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 qodercn_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 qodercn_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 qodercn_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("qodercn 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"qodercn exited with code {exc.exit_code}")
except CLIJSONDecodeError as exc:
    print(f"Could not parse qodercn 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.

Metadata

Release files for qodercn-agent-sdk 1.0.15

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

Source distribution (sdist)

Source distribution for qodercn-agent-sdk 1.0.15
File Size Uploaded
qodercn_agent_sdk-1.0.15.tar.gz 142.9 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for qodercn-agent-sdk 1.0.15
File
qodercn_agent_sdk-1.0.15-py3-none-win_amd64.whl Python 3 none Windows x86-64 Details
qodercn_agent_sdk-1.0.15-py3-none-musllinux_1_2_x86_64.whl Python 3 none Linux musl 1.2+ x86-64 Details
qodercn_agent_sdk-1.0.15-py3-none-musllinux_1_2_aarch64.whl Python 3 none Linux musl 1.2+ ARM64 Details
qodercn_agent_sdk-1.0.15-py3-none-manylinux_2_17_x86_64.whl Python 3 none Linux glibc 2.17+ x86-64 Details
qodercn_agent_sdk-1.0.15-py3-none-manylinux_2_17_aarch64.whl Python 3 none Linux glibc 2.17+ ARM64 Details
qodercn_agent_sdk-1.0.15-py3-none-macosx_11_0_x86_64.whl Python 3 none macOS 11.0+ x86-64 Details
qodercn_agent_sdk-1.0.15-py3-none-macosx_11_0_arm64.whl Python 3 none macOS 11.0+ ARM64 Details

Total release size: 541.8 MB

Release files / qodercn_agent_sdk-1.0.15.tar.gz

Download URL qodercn_agent_sdk-1.0.15.tar.gz
Size 142.9 kB
Tags Source
SHA-256 checksum
How to use checksums
d1894a0089ed604894e5b47a36ad52a93813cf96eed7c973dd10faba149027a7
BLAKE2b-256 checksum
How to use checksums
3d75c124dfea9d274632bec7010a42a1f27856ab6558105d64aa20b93067fd0b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.14

Release files / qodercn_agent_sdk-1.0.15-py3-none-win_amd64.whl

Download URL qodercn_agent_sdk-1.0.15-py3-none-win_amd64.whl
Size 97.9 MB
Tags Python 3 Windows x86-64
SHA-256 checksum
How to use checksums
8ef9d7cf353af6c3f9d034df52b4ca09cbd80a7697e2d1ac07c7cdb2548273d3
BLAKE2b-256 checksum
How to use checksums
61b97bb6b4863d15298e763992d3344b04a488c25a71d529d2ed7c346731ea69
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.14

Release files / qodercn_agent_sdk-1.0.15-py3-none-musllinux_1_2_x86_64.whl

Download URL qodercn_agent_sdk-1.0.15-py3-none-musllinux_1_2_x86_64.whl
Size 74.5 MB
Tags Linux musl 1.2+ x86-64 Python 3
SHA-256 checksum
How to use checksums
631c1c9eda20d4a96f82cfe098d974e2b3ca45d7a6574c61c7cec8a17775edad
BLAKE2b-256 checksum
How to use checksums
be879c25208744f4cc6aff0867e6e8ff8c0f58b2da13078d0490654cdce5c9f9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.14

Release files / qodercn_agent_sdk-1.0.15-py3-none-musllinux_1_2_aarch64.whl

Download URL qodercn_agent_sdk-1.0.15-py3-none-musllinux_1_2_aarch64.whl
Size 74.1 MB
Tags Linux musl 1.2+ ARM64 Python 3
SHA-256 checksum
How to use checksums
5ddf8c0ebd919c090933fe39a0f061fcc0decbe8ca7b09f69fe976e0365122f0
BLAKE2b-256 checksum
How to use checksums
9dbaca8715159f3f70d26bc91ca33aef190848ffa57847f944ebd6f9e7657cc8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.14

Release files / qodercn_agent_sdk-1.0.15-py3-none-manylinux_2_17_x86_64.whl

Download URL qodercn_agent_sdk-1.0.15-py3-none-manylinux_2_17_x86_64.whl
Size 77.8 MB
Tags Linux glibc 2.17+ x86-64 Python 3
SHA-256 checksum
How to use checksums
c3423927400321786c4a30c1a99dd68486f5d57ed8456f4a3bfe7b0a10c42836
BLAKE2b-256 checksum
How to use checksums
938f9bc7536e066a723ae485bc47dba993a417538b35f690e4c42d82706dea25
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.14

Release files / qodercn_agent_sdk-1.0.15-py3-none-manylinux_2_17_aarch64.whl

Download URL qodercn_agent_sdk-1.0.15-py3-none-manylinux_2_17_aarch64.whl
Size 77.4 MB
Tags Linux glibc 2.17+ ARM64 Python 3
SHA-256 checksum
How to use checksums
4f1b8739c7fefca4876e11c281e21df157e72e1b8f576977e9b2ba35e8a54120
BLAKE2b-256 checksum
How to use checksums
891a59a398d6bf8a4eb55471956ce8e99f3181cde9e94bb1f5728cba1bd0b133
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.14

Release files / qodercn_agent_sdk-1.0.15-py3-none-macosx_11_0_x86_64.whl

Download URL qodercn_agent_sdk-1.0.15-py3-none-macosx_11_0_x86_64.whl
Size 71.8 MB
Tags Python 3 macOS 11.0+ x86-64
SHA-256 checksum
How to use checksums
32d596b93bdf3874952648bafeef56067901f16e30b15ee030be579cf4573504
BLAKE2b-256 checksum
How to use checksums
7e08d6b6031f02d8a9e891b2fe20111a9072727b521279d9ccb3694ec6d8a1b7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.14

Release files / qodercn_agent_sdk-1.0.15-py3-none-macosx_11_0_arm64.whl

Download URL qodercn_agent_sdk-1.0.15-py3-none-macosx_11_0_arm64.whl
Size 68.2 MB
Tags Python 3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
cf97c875ad8d53897180de09de5431f2d1a86f26532badefc62b3e146cad235b
BLAKE2b-256 checksum
How to use checksums
4be8e325b107629e46af8465048faf0352162a5d1ae4958419719b5b4821a80e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.14

Release history Release notifications | RSS feed

This release

1.0.15 This release

8 release files

1.0.14

8 release files

1.0.13

8 release 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