Skip to main content

A dependency-free Python SDK that drives the APTO Code CLI over stream-json stdio, mirroring the Claude Agent SDK interface.

Project description

apto-code-sdk

A dependency-free Python SDK for the APTO Code CLI (a Claude-Code-style coding agent). It spawns the apto CLI over stream-json stdio and yields typed messages, mirroring the interface of the official Claude Agent SDK (query() async iterator, an options dataclass, typed message objects).

It exists because the official Claude Agent SDK only locates the claude binary on PATH and offers no way to point at a forked, locally-served CLI. This SDK drives any apto-compatible CLI you name, wrapping the same subprocess + process-group hygiene the APTO research driver uses by hand.

Install

pip install apto-code-sdk

Zero runtime dependencies (Python ≥ 3.10, stdlib only). You must have the apto CLI installed separately (this SDK drives it; it does not bundle it).

Usage

import asyncio
from apto_code_sdk import query, AptoCodeOptions, AssistantMessage, ResultMessage, TextBlock

async def main():
    opts = AptoCodeOptions(
        binary="apto",                       # name on PATH, or an absolute path
        permission_mode="bypassPermissions", # non-interactive one-shot runs need this
        model="deepseek-v4-flash",
    )
    async for message in query(prompt="List three prime numbers.", options=opts):
        if isinstance(message, AssistantMessage):
            for block in message.content:
                if isinstance(block, TextBlock):
                    print(block.text)
        elif isinstance(message, ResultMessage):
            print("turns:", message.num_turns, "cost:", message.total_cost_usd)

asyncio.run(main())

For non-async callers (e.g. a thread-pool driver) there is a blocking collector:

from apto_code_sdk import query_sync
messages = query_sync(prompt="Say hi.", options=opts)

Message types

query() yields, in stream order: SystemMessage (e.g. the init event), AssistantMessage (with TextBlock / ThinkingBlock / ToolUseBlock content), UserMessage (tool results fed back), and finally one ResultMessage — whose arrival ends the iteration. Every message also carries .raw (the original decoded dict) so a field this version does not model yet is never lost.

The SDK reports what the CLI did; it does not judge whether the run "succeeded" for you — that contract belongs to your caller.

Reasoning models & thinking blocks

Reasoning models (e.g. DeepSeek-V4) emit chain-of-thought that is meant to be ephemeral — separated from the answer and dropped between turns. When the deployment separates it (a server reasoning parser plus a router that maps the model's reasoning_content to a thinking block), the SDK surfaces it as a ThinkingBlock and the TextBlock / ResultMessage.result stay clean.

If instead you see the CoT inline in a TextBlock (e.g. …reasoning</think>answer), the chain-of-thought is not being separated upstream — fix it in the model server / router config, not here. The SDK is a faithful transport: it reports the content the CLI produced and never strips text. Leaving leaked CoT inline is harmful to multi-turn agents, since it pollutes the context fed back into later turns.

AptoCodeOptions

field maps to notes
binary argv[0] "apto" (PATH) or an absolute path
cwd, env subprocess env is merged over os.environ
permission_mode --permission-mode default / acceptEdits / plan / bypassPermissions
allowed_tools / disallowed_tools --allowedTools / --disallowedTools comma-joined
system_prompt / append_system_prompt --system-prompt / --append-system-prompt
model --model
max_turns --max-turns
add_dirs --add-dir (repeated)
settings / setting_sources --settings / --setting-sources
session_persistence --no-session-persistence when False default False (one-shot)
include_partial_messages --include-partial-messages
extra_args any flag escape hatch: {"flag": "value" or None}

Runtime knobs (SDK-side, not CLI flags): step_timeout (wall-clock seconds → kills the process group on expiry), post_result_grace (kill a process that lingers past its terminal result — e.g. a sealed container), ready_check (a callable; return True to terminate early once a required output appears), log_path (tee the raw stream-json transcript for provenance).

License

MIT.

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

apto_code_sdk-0.1.0.tar.gz (11.1 kB view details)

Uploaded Source

Built Distribution

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

apto_code_sdk-0.1.0-py3-none-any.whl (15.0 kB view details)

Uploaded Python 3

File details

Details for the file apto_code_sdk-0.1.0.tar.gz.

File metadata

  • Download URL: apto_code_sdk-0.1.0.tar.gz
  • Upload date:
  • Size: 11.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.11

File hashes

Hashes for apto_code_sdk-0.1.0.tar.gz
Algorithm Hash digest
SHA256 bcbfea448bdf5e5669e19a29c0ab76dd24accf3eeedfe55230cd925c09239631
MD5 9a0fef1eb923ce933df2631bca9f2279
BLAKE2b-256 2c0e867f317c4d3b6cb8ec27c8d15ce51da0097e3b0e2241a6ca8373cab41b84

See more details on using hashes here.

File details

Details for the file apto_code_sdk-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: apto_code_sdk-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 15.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.11

File hashes

Hashes for apto_code_sdk-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 25d79fc531fb697522aa2e37ff8967f544140473d936b0b5c2204958c751a4be
MD5 cc2b532b4dda8449f1c3d3bad0126152
BLAKE2b-256 1d0fd62677322f6f08f1ccf9af4e75ae7ce0d1fc9db55ca3bdab355c47224087

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