optio-claudecode
Run Anthropic Claude Code as an optio task — either as a local
subprocess or on a remote host over SSH — with the interactive TUI
embedded in the optio dashboard via an iframe widget served by ttyd.
Install
pip install optio-claudecode
Requires Python 3.11+. Pulls optio-core, optio-host, and asyncssh.
On task start the package auto-installs the host binaries it needs unless told otherwise:
claude— via Anthropic's vendor script (https://claude.ai/install.sh)ttyd— static binary fromtsl0922/ttydGitHub Releases
Quick start
from optio_claudecode import (
ClaudeCodeTaskConfig,
create_claudecode_task,
)
def get_tasks():
return [
create_claudecode_task(
process_id="example-task",
name="Example",
config=ClaudeCodeTaskConfig(
consumer_instructions="Please write a haiku about MongoDB.",
credentials_json=load_user_creds_from_db(user_id),
# Optional: skip interactive permission prompts for autonomous flows.
permission_mode="bypassPermissions",
),
)
]
credentials_json is treated as an opaque payload and written verbatim
to <workdir>/home/.claude/.credentials.json (mode 0600) before claude
launches. Format follows whatever Anthropic's CLI currently expects.
How it works
Each task gets a workdir tempdir (/tmp/optio-claudecode-<uuid>/). The
ttyd process is launched with HOME=<workdir>/home, so claude reads
all its state — credentials, settings, session history — strictly from
the per-task workdir and never touches the host user's real
~/.claude/. Two tasks on the same host can run concurrently without
shared-state races.
The agent is given a <workdir>/CLAUDE.md that includes the
optio.log coordination protocol — STATUS: / DELIVERABLE: /
DONE / ERROR — verbatim from optio_host.agents. The same protocol
is used by optio-opencode, so the same consumer_instructions can be
swapped between the two packages.
See docs/2026-05-28-optio-claudecode-design.md for the full design.
Messages
use_client_messages(bool, defaultFalse) — enable theCLIENT_MESSAGE:log keyword: the agent can push{keyword, data}messages to the browser session that launched the task (surfaced via optio-ui'sonClientMessage).on_caller_message(async callback, defaultNone) — enable theCALLER_MESSAGE:log keyword: the agent can push{keyword, data}messages to your application. Signature(hook_ctx, keyword, data) -> str | None; a non-None return is sent back to the agent as feedback. Keywords that are not enabled are absent from both the parser and the agent-facing protocol documentation.
Conversation mode
With mode="conversation" the task runs claude headlessly (no ttyd, no
iframe) over its bidirectional stream-json stdio protocol, and the
launching code receives a live Conversation object — send messages,
subscribe to events and answers, gate tool permissions, interrupt,
close:
config = ClaudeCodeTaskConfig(
consumer_instructions=None, # defaults to a plain conversation prompt
credentials_json=...,
mode="conversation",
host_protocol=False, # no optio.log keyword channel
permission_mode="acceptEdits",
)
# ... register the task, then:
conv = await optio.launch_and_await_result("example-task", session_id=None)
conv.on_message(lambda text: print("claude:", text))
await conv.send("hello")
await conv.close()
All new config fields default to existing behavior (mode="iframe",
host_protocol=True, permission_gate=False), so existing callers run
unchanged. See docs/2026-06-10-claudecode-conversation-gate-design.md.
Dashboard conversation UI
With the opt-in conversation_ui=True (conversation mode only) the
task additionally starts a per-task listener that streams the raw
conversation events (replay + live) through the optio widget proxy and
accepts send / interrupt / permission requests, so the session can be
monitored and driven from the browser. The matching React chat widget
ships in the engine-neutral optio-conversation-ui package; register it
in your host app via registerConversationWidget() (one registration
serves both claudecode and opencode — each task self-declares its engine
via widgetData.protocol). See
docs/2026-06-10-claudecode-conversation-ui-design.md.
config = ClaudeCodeTaskConfig(
consumer_instructions="", # defaulted conversation prompt
credentials_json=...,
mode="conversation",
conversation_ui=True,
permission_gate=True, # approve/deny tool use in the browser
)
Metadata
Release files for optio-claudecode 0.6.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| optio_claudecode-0.6.3.tar.gz | 175.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| optio_claudecode-0.6.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 266.7 kB
Release files / optio_claudecode-0.6.3.tar.gz
| Download URL | optio_claudecode-0.6.3.tar.gz |
|---|---|
| Size | 175.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ec867683a6b38330a59d2009efb4b52e8d5a72cdfdc653bccc6ab28367d46c6d
|
|
BLAKE2b-256 checksum How to use checksums |
36e90781c6ca761b4f73dc00e50f4a15db8364c7aed072a02b6b50e3145cf780
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.5
|
Release files / optio_claudecode-0.6.3-py3-none-any.whl
| Download URL | optio_claudecode-0.6.3-py3-none-any.whl |
|---|---|
| Size | 91.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1e1b46548aedd57e9954e889cf0a67a8e21971b6d2cc0aead1d916706476a66f
|
|
BLAKE2b-256 checksum How to use checksums |
32ad218ddb1991d838f8f064bd0d04d996f1e664f68ea2bde6c855b68cdfcd53
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.5
|