Skip to main content

pyclaudecli

PyPI Python versions License: MIT Downloads

A Python library that wraps the Claude Code CLI (claude) so you can drive it from Python instead of shelling out by hand: one-shot prompts, JSON/streaming output, background agents, authentication, MCP servers, plugins, and the rest of the CLI's surface.

It's a thin wrapper, not a reimplementation — every call runs the real claude binary, so it always reflects whatever version, auth, and config you have installed locally.

Contents

Install

pip install pyclaudecli

Requires the claude CLI itself to be installed and on PATH (see the Claude Code docs).

Quickstart

from pyclaudecli import ClaudeCLI

claude = ClaudeCLI()

# One-shot prompt
print(claude.prompt("Summarize this repo's README.", model="haiku"))

Setup

from pyclaudecli import ClaudeCLI

# Defaults: binary="claude" on PATH, inherited cwd/env, no timeout
claude = ClaudeCLI()

# Pointing at a specific binary/project, with a default timeout for every call
claude = ClaudeCLI(
    "claude",
    cwd="/path/to/project",
    env={"ANTHROPIC_API_KEY": "sk-ant-..."},
    timeout=120,
)

Command-line usage

The package also installs a minimal pyclaudecli command (and python -m pyclaudecli) for quick one-off prompts — for anything beyond that, use ClaudeCLI directly.

pyclaudecli "What's 2+2?"                    # defaults to model "haiku"
pyclaudecli --model sonnet "Explain this diff"
pyclaudecli -m sonnet "Explain this diff"

python -m pyclaudecli "Hello, Claude!"

Errors

All CLI failures raise ClaudeCLIError (or ClaudeNotFoundError / ClaudeTimeoutError), carrying returncode, stdout, stderr, and cmd.

from pyclaudecli import ClaudeCLI, ClaudeCLIError, ClaudeNotFoundError, ClaudeTimeoutError

claude = ClaudeCLI()

try:
    claude.prompt("Do something", model="haiku", timeout=30)
except ClaudeTimeoutError as exc:
    print("timed out:", exc.cmd)
except ClaudeNotFoundError as exc:
    print("claude binary not on PATH:", exc)
except ClaudeCLIError as exc:
    print(exc.returncode, exc.stdout, exc.stderr)

build_flags

The helper ClaudeCLI uses internally to turn a {python_name: value} dict into CLI flags — handy if you're composing your own extra_flags or calling .run() directly. None/False are omitted, True becomes a bare flag, lists/tuples repeat the flag followed by each value, and anything else becomes the flag plus str(value).

from pyclaudecli import build_flags

build_flags({"model": "haiku", "verbose": True, "quiet": False, "add_dir": ["a", "b"]})
# ["--model", "haiku", "--verbose", "--add-dir", "a", "b"]

Every method, with an example

All examples assume:

from pyclaudecli import ClaudeCLI

claude = ClaudeCLI()

Raw / internal

# .run() — lowest-level call; returns a CommandResult(returncode, stdout, stderr)
result = claude.run(["--version"], check=False)
print(result.returncode, result.stdout)

Version / health

claude.version()   # "claude --version" -> "1.2.3"
claude.doctor()    # "claude doctor" -> health-check report
claude.update()    # "claude update" -> checks for and installs updates

claude.install()                       # "claude install" (latest default)
claude.install("stable")               # "claude install stable"
claude.install("1.2.3", force=True)    # "claude install 1.2.3 --force"

Prompting

# One-shot prompt -> plain text
claude.prompt("Summarize this repo's README.", model="haiku")

# Structured result (cost, session id, etc.)
result = claude.prompt_json("What's 2+2?", model="haiku")
print(result["result"], result["total_cost_usd"])

# Live streaming events
for event in claude.prompt_stream("Write a haiku about tests.", model="haiku"):
    print(event["type"])

# Full option surface
claude.prompt(
    "Refactor this function for clarity.",
    model="sonnet",
    output_format="json",
    system_prompt="You are a terse senior engineer.",
    append_system_prompt="Always answer in bullet points.",
    allowed_tools=["Read", "Edit"],
    disallowed_tools=["Bash"],
    add_dir=["../shared-lib"],
    permission_mode="acceptEdits",
    mcp_config=["./mcp.json"],
    settings="./claude-settings.json",
    resume="session-id-123",
    fork_session=True,
    effort="high",
    fallback_model="haiku",
    max_budget_usd=0.50,
    json_schema='{"type": "object"}',
    betas=["some-beta-flag"],
    no_session_persistence=True,
    dangerously_skip_permissions=False,
    restricted=True,
    input_text="piped stdin content",
    timeout=60,
    extra_flags={"worktree": True},  # anything without a named parameter
)

# continue_session=True appends --continue (keeps typing in the latest session)
claude.prompt("And now add tests for it.", continue_session=True)

Background sessions ("agents")

session_id = claude.start_background("Refactor the auth module", model="sonnet")

claude.list_agents()                          # all sessions, as a list of dicts
claude.list_agents(all=True, cwd="/repo")      # include finished ones, scoped to a project

claude.attach(session_id)                      # interactive; requires a real TTY
claude.logs(session_id)                        # raw terminal snapshot
claude.logs(session_id, strip_ansi=True)       # best-effort plain text

claude.stop(session_id)                        # stop, keep state
claude.respawn(session_id)                     # restart one stopped session
claude.respawn(all=True)                       # restart every stopped session
claude.rm(session_id)                          # delete a stopped session

Auth

claude.auth_status()                # {"loggedIn": True, "email": "...", ...}
claude.auth_status(as_json=False)   # human-readable text instead

# Non-interactive login: supply the code yourself
claude.auth_login(code="123456")

# Or fetch the code programmatically from the printed sign-in URL
claude.auth_login(code_provider=lambda url: fetch_code_from_my_browser(url))

# Route the printed sign-in URL/output somewhere other than stdout
claude.auth_login(on_output=lambda chunk: log.info(chunk), console=True, timeout=120)

claude.auth_logout()
claude.setup_token()   # interactive; sets up a long-lived auth token

MCP servers

claude.mcp_list()
claude.mcp_get("sentry")

claude.mcp_add("sentry", "https://mcp.sentry.dev/mcp", transport="http")
claude.mcp_add(
    "local-tool", "node", "server.js",
    transport="stdio", env=["API_KEY=abc"], scope="project",
)

claude.mcp_add_json("sentry", {"type": "http", "url": "https://mcp.sentry.dev/mcp"})
claude.mcp_add_from_claude_desktop(scope="user")

claude.mcp_remove("sentry", scope="project")
claude.mcp_login("sentry")             # interactive OAuth
claude.mcp_logout("sentry")
claude.mcp_reset_project_choices()

Plugins

claude.plugin_list()
claude.plugin_list(as_json=True)

claude.plugin_install("some-plugin", yes=True)
claude.plugin_install("some-plugin@my-marketplace", scope="user", as_json=True)

claude.plugin_uninstall("some-plugin", yes=True, prune=True)
claude.plugin_enable("some-plugin")
claude.plugin_disable("some-plugin")
claude.plugin_disable(all=True)        # disable every plugin

claude.plugin_update("some-plugin", yes=True)
claude.plugin_details("some-plugin")
claude.plugin_validate("./my-plugin", strict=True, as_json=True)
claude.plugin_prune(dry_run=True)

claude.plugin_marketplace_list()
claude.plugin_marketplace_add("https://github.com/org/marketplace-repo")
claude.plugin_marketplace_remove("marketplace-name")
claude.plugin_marketplace_update()             # update all
claude.plugin_marketplace_update("marketplace-name")

Project state

claude.project_purge()                 # purge state for the current project
claude.project_purge("/path/to/repo")  # or for a specific path

Auto mode

claude.auto_mode_config()      # effective classifier config, as a dict
claude.auto_mode_defaults()    # shipped default rules, as a dict
claude.auto_mode_reset()       # remove custom rules from user settings
claude.auto_mode_critique()    # AI feedback on your custom rules

Misc

claude.import_config("cursor", dry_run=True, yes=True)   # source: codex, gemini, or cursor

claude.ultrareview()                                 # review the current branch
claude.ultrareview("main")                            # review against a base branch
claude.ultrareview(482, as_json=True, post=True)       # review a PR, post results, get JSON

# Long-running server: returns a Popen handle, doesn't block
gateway = claude.start_gateway(config="./gateway.json")
...
gateway.terminate()

See ClaudeCLI's docstrings for the exact CLI flags behind each method — it covers every top-level claude command (auth, mcp, plugin, project, agents/background sessions, auto-mode, doctor, update, install, import, ultrareview, gateway) plus the main prompt flags. Anything not exposed as a named parameter can still be passed through via each method's extra_flags dict.

Development

git clone https://github.com/Suriya-Ravichandran/pyclaudecli.git
cd pyclaudecli
pip install -e .
pytest

License

MIT

Release files for pyclaudecli 1.0.1

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

Source distribution (sdist)

Source distribution for pyclaudecli 1.0.1
File Size Uploaded
pyclaudecli-1.0.1.tar.gz 14.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pyclaudecli 1.0.1
File Interpreter ABI Platform
pyclaudecli-1.0.1-py3-none-any.whl Python 3 none any Details

Total release size: 30.4 kB

Release files / pyclaudecli-1.0.1.tar.gz

Download URL pyclaudecli-1.0.1.tar.gz
Size 14.9 kB
Tags Source
SHA-256 checksum
How to use checksums
e43c4428fd6396f5230b17226492431406c48056d403267a0b4caaa24f95fea1
BLAKE2b-256 checksum
How to use checksums
d7cb4c852c30b8b0c41ed07640c562141ca35514db93a40317394303dbb0bf37
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.14 {"installer":{"name":"uv","version":"0.12.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / pyclaudecli-1.0.1-py3-none-any.whl

Download URL pyclaudecli-1.0.1-py3-none-any.whl
Size 15.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
481d33ee93828f34e85d584ce60ac32116a587cd7c9fb148752b393969592315
BLAKE2b-256 checksum
How to use checksums
8020054d80b57246207cdaeb557c376bfc3c45d2fa448fa880ef0e9cc7cfc7c0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.14 {"installer":{"name":"uv","version":"0.12.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

1.0.6

2 release files

1.0.5

2 release files

1.0.4

2 release files

1.0.3

2 release files

1.0.2

2 release files

This release

1.0.1 This release

2 release files

1.0.0

2 release files

0.1.0

2 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