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.

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.14

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.14
File Size Uploaded
qodercn_agent_sdk-1.0.14.tar.gz 138.2 kB Details

Built distributions (wheels)

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

Total release size: 356.8 MB

Release files / qodercn_agent_sdk-1.0.14.tar.gz

Download URL qodercn_agent_sdk-1.0.14.tar.gz
Size 138.2 kB
Tags Source
SHA-256 checksum
How to use checksums
7d0912fe238f6b0463896cb70879e1b8ee46e3cb29534668b3fe8b09d630b5a5
BLAKE2b-256 checksum
How to use checksums
84c53a2c9ea801eeadfcc655bd45a8a78fea64d493c08e730260332a7c7e578b
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.14-py3-none-win_amd64.whl

Download URL qodercn_agent_sdk-1.0.14-py3-none-win_amd64.whl
Size 64.9 MB
Tags Python 3 Windows x86-64
SHA-256 checksum
How to use checksums
81955d20386d3000edc58eff2f6adc0f79011ee2361568807f617cf18dfb25db
BLAKE2b-256 checksum
How to use checksums
6193c47ef5d0976a7d7a84d2946c5b3ccc082286fa4ea1a2dd9fd441f646d2dd
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.14-py3-none-musllinux_1_2_x86_64.whl

Download URL qodercn_agent_sdk-1.0.14-py3-none-musllinux_1_2_x86_64.whl
Size 51.4 MB
Tags Linux musl 1.2+ x86-64 Python 3
SHA-256 checksum
How to use checksums
1c51abaee64698497ca2c543bfdda61a03918ada96ec9bb871b2caa0ca439b1e
BLAKE2b-256 checksum
How to use checksums
456706e306184e064e35c224a5b6ce52b245bdf9e0866436de0c223e4d9c591e
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.14-py3-none-musllinux_1_2_aarch64.whl

Download URL qodercn_agent_sdk-1.0.14-py3-none-musllinux_1_2_aarch64.whl
Size 50.7 MB
Tags Linux musl 1.2+ ARM64 Python 3
SHA-256 checksum
How to use checksums
8c7f34c6a5927691b473a1105232b70e6bfcd321680d9f69149798b1a459479a
BLAKE2b-256 checksum
How to use checksums
bf4db37bf10368425c50d5ccafd2511424b8e6a94f117571cfbf557b3a256465
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.14-py3-none-manylinux_2_17_x86_64.whl

Download URL qodercn_agent_sdk-1.0.14-py3-none-manylinux_2_17_x86_64.whl
Size 52.2 MB
Tags Linux glibc 2.17+ x86-64 Python 3
SHA-256 checksum
How to use checksums
4455e618453dcb6acb03423d63071be353791e9d2b2b46eab288230a259a59f0
BLAKE2b-256 checksum
How to use checksums
83f62b277226557079fef3b317e476d072ad27c1d8a2f619ce3fd24492a805cd
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.14-py3-none-manylinux_2_17_aarch64.whl

Download URL qodercn_agent_sdk-1.0.14-py3-none-manylinux_2_17_aarch64.whl
Size 52.0 MB
Tags Linux glibc 2.17+ ARM64 Python 3
SHA-256 checksum
How to use checksums
4ae48ac27fdcfac90129a071ca88d83d634327a61eb2ddb6b8c38f5ce1c8ffeb
BLAKE2b-256 checksum
How to use checksums
f9880aa8c30b4d546fbec482f6cf0c88167f4b11cc72964b797dd2d88e96b06b
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.14-py3-none-macosx_11_0_x86_64.whl

Download URL qodercn_agent_sdk-1.0.14-py3-none-macosx_11_0_x86_64.whl
Size 44.7 MB
Tags Python 3 macOS 11.0+ x86-64
SHA-256 checksum
How to use checksums
4a02d8f90a89a6d1cb5f1207f90386190c01720a22f047f4f2707062703bfb66
BLAKE2b-256 checksum
How to use checksums
f3b949cd3dc6f7a9d92b85df2cb7d371fe90a2c31dd9c71e9a0db8bc1fd6bda2
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.14-py3-none-macosx_11_0_arm64.whl

Download URL qodercn_agent_sdk-1.0.14-py3-none-macosx_11_0_arm64.whl
Size 40.7 MB
Tags Python 3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
e1a905ea0cdb38e605062ac8d3d233e5a00e0f3e34834c8d6fa10eeb2a7e5593
BLAKE2b-256 checksum
How to use checksums
1f3a763910eb645bca23c361595c8dca5e199c4ac4f2018e14c0b2423f87d00a
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

1.0.15

8 release files

This release

1.0.14 This release

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