Run Anthropic Claude Code as an optio task; local subprocess or remote via SSH; ttyd-served TUI iframe.
Project description
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
)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file optio_claudecode-0.3.3.tar.gz.
File metadata
- Download URL: optio_claudecode-0.3.3.tar.gz
- Upload date:
- Size: 130.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
23ebe50a672cb47c055f001a62c21950d09237611e74a94a1597eb9cf946ca47
|
|
| MD5 |
3348ea2cd5c688a910dab506f855f952
|
|
| BLAKE2b-256 |
f105e10afd34c701bf0888ca3d63df867ea84621a4bd09d7a9623dd60a2baa9f
|
File details
Details for the file optio_claudecode-0.3.3-py3-none-any.whl.
File metadata
- Download URL: optio_claudecode-0.3.3-py3-none-any.whl
- Upload date:
- Size: 75.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
188007e56aa3d353a67997d728d7201902197510b3475e057f3fad5f0e7f0441
|
|
| MD5 |
5a94085c7c7ace79295bf75bbc82efc1
|
|
| BLAKE2b-256 |
e7e9da3191c19702c78894a8d98508ca3edcd92786da5ed60f32cfcf5c59e5e7
|