scitex_agent_container API Reference

Top-level package surface re-exported from scitex_agent_container. Use scitex-agent-container list-python-apis for the authoritative runtime enumeration.

SciTeX Agent Container – Declarative agent management.

Provides a YAML-based framework for defining, managing, and orchestrating AI coding agent instances across container runtimes.

Public surface — CLI-tree-shaped noun submodules:

import scitex_agent_container as sac

sac.agent.list()                  # `sac agent list`
sac.agent.start("head-nas")       # `sac agent start head-nas`
sac.db.query(table="instances")   # `sac db query --table=instances`
sac.host.show()                   # `sac host show`
sac.skills.get("02_quick-start")  # `sac skills get 02_quick-start`

Each noun submodule (agent, db, host, image, template, account, skills, mcp) re-exports its verbs under bare names that mirror the CLI subcommand tree. The same function objects power both the Python API and the MCP server (per scitex MCP §6 parity).

Lifecycle helpers that take a shared Registry instance live at scitex_agent_container._lifecycle.lifecycle for callers that need them. The submodule verbs go through the CLI for JSON-friendly input/output.

class scitex_agent_container.AgentConfig(name, runtime='claude-code', image='', dockerfile='', model='sonnet', workdir='~/proj', python_venv='', env=<factory>, env_files=<factory>, screen_name='', labels=<factory>, container=<factory>, claude=<factory>, health=<factory>, watchdog=<factory>, restart=<factory>, autonomous=<factory>, apptainer=<factory>, hooks=<factory>, listen=<factory>, extensions=<factory>, telegram=<factory>, remote=<factory>, skills=<factory>, context_management=<factory>, startup_commands=<factory>, startup=<factory>, mcp_servers=<factory>, multiplexer='tmux', hosts_spec=<factory>, scheduling=<factory>, orochi=<factory>, config_path='')[source]

Bases: object

Parsed agent configuration from a YAML definition file.

name: str
runtime: str = 'claude-code'
image: str = ''
dockerfile: str = ''
model: str = 'sonnet'
workdir: str = '~/proj'
python_venv: str = ''
env: dict[str, str]
env_files: list[str]
screen_name: str = ''
labels: dict[str, str]
container: ContainerSpec
claude: ClaudeSpec
health: HealthSpec
watchdog: WatchdogSpec
restart: RestartSpec
autonomous: AutonomousSpec
apptainer: ApptainerSpec
hooks: dict[str, list[str]]
listen: list[ListenPort]
extensions: Dict[str, Any]
telegram: TelegramSpec
remote: RemoteSpec
skills: SkillsSpec
context_management: ContextManagementConfig
startup_commands: list[StartupCommand]
startup: StartupSpec
mcp_servers: dict[str, dict]
multiplexer: str = 'tmux'
hosts_spec: HostsSpec
__init__(name, runtime='claude-code', image='', dockerfile='', model='sonnet', workdir='~/proj', python_venv='', env=<factory>, env_files=<factory>, screen_name='', labels=<factory>, container=<factory>, claude=<factory>, health=<factory>, watchdog=<factory>, restart=<factory>, autonomous=<factory>, apptainer=<factory>, hooks=<factory>, listen=<factory>, extensions=<factory>, telegram=<factory>, remote=<factory>, skills=<factory>, context_management=<factory>, startup_commands=<factory>, startup=<factory>, mcp_servers=<factory>, multiplexer='tmux', hosts_spec=<factory>, scheduling=<factory>, orochi=<factory>, config_path='')
scheduling: SchedulingSpec
orochi: OrochiSpec
config_path: str = ''
property expanded_workdir: str
scitex_agent_container.load_config(path)[source]

Load and validate a YAML config, returning an AgentConfig.

Only scitex-agent-container/v3 is accepted. Older apiVersions (v1, v2) raise loud validation errors — no backward compatibility.

Return type:

AgentConfig

scitex_agent_container.validate_config(path)[source]

Validate a config file and return list of errors (empty = valid).

Return type:

list[str]

class scitex_agent_container.Registry(registry_dir=None)[source]

Bases: object

File-based registry for tracking running agent instances.

__init__(registry_dir=None)[source]
add(name, config_path, screen_name, pid=None)[source]

Register an agent as running.

Return type:

None

remove(name)[source]

Remove an agent from the registry.

Return type:

None

get(name)[source]

Get registry entry for an agent, or None if not found.

Return type:

dict | None

list_all()[source]

List all registered agents.

Return type:

list[dict]

exists(name)[source]

Check if an agent is registered.

Return type:

bool

cleanup_stale()[source]

Remove entries whose multiplexer sessions no longer exist.

Probes tmux first (tmux has-session), then screen (-ls). An entry is removed only when the session is absent from both multiplexers. This makes cleanup safe on mixed fleets where agents may run under either tmux or GNU screen.

Returns count removed.

Return type:

int

Config

YAML config loading and validation for agent definitions.

Public API:

AgentConfig, load_config, validate_config, resolve_config ContainerSpec, ClaudeSpec, HealthSpec, WatchdogSpec, RestartSpec, TelegramSpec, RemoteSpec, SkillsSpec, StartupCommand

class scitex_agent_container.config.AgentConfig(name, runtime='claude-code', image='', dockerfile='', model='sonnet', workdir='~/proj', python_venv='', env=<factory>, env_files=<factory>, screen_name='', labels=<factory>, container=<factory>, claude=<factory>, health=<factory>, watchdog=<factory>, restart=<factory>, autonomous=<factory>, apptainer=<factory>, hooks=<factory>, listen=<factory>, extensions=<factory>, telegram=<factory>, remote=<factory>, skills=<factory>, context_management=<factory>, startup_commands=<factory>, startup=<factory>, mcp_servers=<factory>, multiplexer='tmux', hosts_spec=<factory>, scheduling=<factory>, orochi=<factory>, config_path='')[source]

Bases: object

Parsed agent configuration from a YAML definition file.

name: str
runtime: str = 'claude-code'
image: str = ''
dockerfile: str = ''
model: str = 'sonnet'
workdir: str = '~/proj'
python_venv: str = ''
env: dict[str, str]
env_files: list[str]
screen_name: str = ''
labels: dict[str, str]
container: ContainerSpec
claude: ClaudeSpec
health: HealthSpec
watchdog: WatchdogSpec
restart: RestartSpec
autonomous: AutonomousSpec
apptainer: ApptainerSpec
hooks: dict[str, list[str]]
listen: list[ListenPort]
extensions: Dict[str, Any]
telegram: TelegramSpec
remote: RemoteSpec
skills: SkillsSpec
context_management: ContextManagementConfig
startup_commands: list[StartupCommand]
startup: StartupSpec
mcp_servers: dict[str, dict]
multiplexer: str = 'tmux'
hosts_spec: HostsSpec
__init__(name, runtime='claude-code', image='', dockerfile='', model='sonnet', workdir='~/proj', python_venv='', env=<factory>, env_files=<factory>, screen_name='', labels=<factory>, container=<factory>, claude=<factory>, health=<factory>, watchdog=<factory>, restart=<factory>, autonomous=<factory>, apptainer=<factory>, hooks=<factory>, listen=<factory>, extensions=<factory>, telegram=<factory>, remote=<factory>, skills=<factory>, context_management=<factory>, startup_commands=<factory>, startup=<factory>, mcp_servers=<factory>, multiplexer='tmux', hosts_spec=<factory>, scheduling=<factory>, orochi=<factory>, config_path='')
scheduling: SchedulingSpec
orochi: OrochiSpec
config_path: str = ''
property expanded_workdir: str
class scitex_agent_container.config.ClaudeSpec(channels=<factory>, flags=<factory>, session='continue-or-new', continue_max_age_minutes=None, resume_id='', auto_accept=True)[source]

Bases: object

channels: list[str]
flags: list[str]
session: str = 'continue-or-new'
continue_max_age_minutes: int | None = None
resume_id: str = ''
auto_accept: bool = True
__init__(channels=<factory>, flags=<factory>, session='continue-or-new', continue_max_age_minutes=None, resume_id='', auto_accept=True)
class scitex_agent_container.config.ContainerSpec(runtime='none', image='scitex-agent-container:latest', volumes=<factory>, network='host', mount_host_claude=False)[source]

Bases: object

runtime: str = 'none'
image: str = 'scitex-agent-container:latest'
volumes: list[str]
network: str = 'host'
mount_host_claude: bool = False
__init__(runtime='none', image='scitex-agent-container:latest', volumes=<factory>, network='host', mount_host_claude=False)
class scitex_agent_container.config.ContextManagementConfig(trigger_at_percent=70.0, strategy='noop', warn_before_n_checks=0, check_interval_seconds=300, state_file='~/.scitex/agent-container/state/<agent>.json')[source]

Bases: object

Context-lifecycle policy for an agent.

Defaults mirror strategy="noop" so absence of the context_management block preserves existing behavior (sensor disabled).

trigger_at_percent: float = 70.0
strategy: str = 'noop'
warn_before_n_checks: int = 0
check_interval_seconds: int = 300
state_file: str = '~/.scitex/agent-container/state/<agent>.json'
property enabled: bool
__init__(trigger_at_percent=70.0, strategy='noop', warn_before_n_checks=0, check_interval_seconds=300, state_file='~/.scitex/agent-container/state/<agent>.json')
class scitex_agent_container.config.HealthSpec(enabled=False, interval=30, timeout=5, method='multiplexer-alive')[source]

Bases: object

enabled: bool = False
interval: int = 30
timeout: int = 5
method: str = 'multiplexer-alive'
__init__(enabled=False, interval=30, timeout=5, method='multiplexer-alive')
class scitex_agent_container.config.HookSpec(pre_start=<factory>, post_start=<factory>, pre_stop=<factory>, post_stop=<factory>, on_compact=<factory>, on_restart=<factory>, on_diff=<factory>)[source]

Bases: object

All hook points supported by the container.

Each entry is a list of opaque commands — shell strings or http(s) URLs. The container executes them fire-and-forget; errors are logged but never raised to the caller. Absent keys default to empty lists (feature disabled).

pre_start: list[str]
post_start: list[str]
pre_stop: list[str]
post_stop: list[str]
on_compact: list[str]
on_restart: list[str]
on_diff: list[str]
counts()[source]
Return type:

dict[str, int]

__init__(pre_start=<factory>, post_start=<factory>, pre_stop=<factory>, post_stop=<factory>, on_compact=<factory>, on_restart=<factory>, on_diff=<factory>)
class scitex_agent_container.config.HostsSpec(host='', hosts=<factory>)[source]

Bases: object

Where an agent should run, in either singleton or multi-instance form.

Mutually exclusive — exactly one of host or hosts may be set:

  • host (singular) — exactly one instance runs:
    • empty / absent: local singleton (runs wherever sac is invoked)

    • string: pinned to that host

    • list: priority order; first available host wins (fallback chain)

  • hosts (plural) — multiple instances run, one per host:
    • “all”: one per fleet host (replaces the old per-host mode)

    • list of host names: one per listed host (subset)

Validator (in _validation.py) enforces mutual exclusion + types. Loader composes effective ids: hosts triggers the <name>-<HOST> suffix; host keeps the bare name.

host: str | list[str] = ''
hosts: str | list[str]
__init__(host='', hosts=<factory>)
class scitex_agent_container.config.ListenPort(port=0, proto='tcp', path='', name='', owner='')[source]

Bases: object

Declaration of a port/socket an external tool binds on behalf of an agent.

The container NEVER binds these — it just validates the shape and echoes them in status --json so orchestrators can see what sidecars are expected to exist. owner is free-form (e.g. "orochi") to identify the plugin that actually listens.

port: int = 0
proto: str = 'tcp'
path: str = ''
name: str = ''
owner: str = ''
__init__(port=0, proto='tcp', path='', name='', owner='')
class scitex_agent_container.config.OrochiSpec(enabled=False, hosts=<factory>, port=8559, token_env='SCITEX_OROCHI_TOKEN', channels=<factory>, heartbeat_interval=60)[source]

Bases: object

enabled: bool = False
hosts: list[str]
port: int = 8559
token_env: str = 'SCITEX_OROCHI_TOKEN'
channels: list[str]
heartbeat_interval: int = 60
__init__(enabled=False, hosts=<factory>, port=8559, token_env='SCITEX_OROCHI_TOKEN', channels=<factory>, heartbeat_interval=60)
class scitex_agent_container.config.ReadyPattern(regex='')[source]

Bases: object

A single regex the pane content must match for the agent to be ready.

regex: str = ''
__init__(regex='')
class scitex_agent_container.config.RemoteSpec(hops=<factory>, host='', user='', key='', port=22, timeout=60, login_shell=True, no_preflight=False)[source]

Bases: object

hops: list
host: str = ''
user: str = ''
key: str = ''
port: int = 22
timeout: int = 60
login_shell: bool = True
no_preflight: bool = False
property is_remote: bool

Return True if this agent should be deployed via SSH.

__init__(hops=<factory>, host='', user='', key='', port=22, timeout=60, login_shell=True, no_preflight=False)
class scitex_agent_container.config.RestartSpec(policy='never', max_retries=3, backoff_initial=30, backoff_max=300, backoff_multiplier=2)[source]

Bases: object

policy: str = 'never'
max_retries: int = 3
backoff_initial: int = 30
backoff_max: int = 300
backoff_multiplier: int = 2
__init__(policy='never', max_retries=3, backoff_initial=30, backoff_max=300, backoff_multiplier=2)
class scitex_agent_container.config.SchedulingSpec(mode='per-host', preferred_host='', fallback_hosts=<factory>)[source]

Bases: object

Fleet-wide scheduling policy for an agent (shared-host layout).

mode controls effective-id composition and launch-skip behavior:
  • per-host (default): agent is started on every host that runs sac agent start <name>; the effective id is <metadata.name>-<HOST> unless the name already ends with -<HOST>.

  • singleton: exactly one instance fleet-wide. The effective id stays as the bare <metadata.name>. Only launched on preferred-host; on other hosts the launch is a no-op.

fallback-hosts is recorded for observability but not acted on automatically — manual failover today.

mode: str = 'per-host'
preferred_host: str = ''
fallback_hosts: list[str]
__init__(mode='per-host', preferred_host='', fallback_hosts=<factory>)
class scitex_agent_container.config.SkillsSpec(required=<factory>, available=<factory>, injection_mode='at-import', match_by=<factory>, match_style='exact')[source]

Bases: object

required: list[str]
available: list[str]
injection_mode: str = 'at-import'
match_by: list[str]
match_style: str = 'exact'
__init__(required=<factory>, available=<factory>, injection_mode='at-import', match_by=<factory>, match_style='exact')
class scitex_agent_container.config.StartupCommand(delay=0, command='')[source]

Bases: object

delay: int = 0
command: str = ''
__init__(delay=0, command='')
class scitex_agent_container.config.StartupSpec(ready_patterns=<factory>, ready_idle_ticks=3, ready_poll_interval_seconds=0.5, ready_timeout_seconds=60.0, on_timeout='capture_and_proceed', commands=<factory>)[source]

Bases: object

Opt-in ready-state gate for startup commands (todo#291).

When ready_patterns is empty, legacy fire-and-hope behavior is preserved. Otherwise agent_start polls the tmux pane content and only dispatches commands once all patterns match against the tail of the capture AND the pane has been byte-identical for ready_idle_ticks consecutive polls.

ready_patterns: list[ReadyPattern]
ready_idle_ticks: int = 3
ready_poll_interval_seconds: float = 0.5
ready_timeout_seconds: float = 60.0
on_timeout: str = 'capture_and_proceed'
commands: list[StartupCommand]
__init__(ready_patterns=<factory>, ready_idle_ticks=3, ready_poll_interval_seconds=0.5, ready_timeout_seconds=60.0, on_timeout='capture_and_proceed', commands=<factory>)
class scitex_agent_container.config.TelegramSpec(bot_token_env='SCITEX_AGENT_CONTAINER_TELEGRAM_BOT_TOKEN', allowed_users=<factory>, auto_connect=True, greeting='')[source]

Bases: object

bot_token_env: str = 'SCITEX_AGENT_CONTAINER_TELEGRAM_BOT_TOKEN'
allowed_users: list[str]
auto_connect: bool = True
greeting: str = ''
__init__(bot_token_env='SCITEX_AGENT_CONTAINER_TELEGRAM_BOT_TOKEN', allowed_users=<factory>, auto_connect=True, greeting='')
class scitex_agent_container.config.WatchdogSpec(enabled=False, interval=1.5, resp_y_n='1', resp_y_y_n='2', resp_waiting='/speak-and-call')[source]

Bases: object

enabled: bool = False
interval: float = 1.5
resp_y_n: str = '1'
resp_y_y_n: str = '2'
resp_waiting: str = '/speak-and-call'
__init__(enabled=False, interval=1.5, resp_y_n='1', resp_y_y_n='2', resp_waiting='/speak-and-call')
scitex_agent_container.config.compose_effective_name(raw_name, hosts_spec, hostname)[source]

Return the effective agent id given dir-derived name + host/hosts + host.

Return type:

str

Rules:
  • If hosts: is set (multi-instance), append -<hostname> so each host’s instance has a unique id. Idempotent — names that already end with -<hostname> are not double-suffixed.

  • Otherwise (host: set, or both empty = local singleton): keep the bare raw_name. Singleton id stays stable across hosts.

scitex_agent_container.config.load_config(path)[source]

Load and validate a YAML config, returning an AgentConfig.

Only scitex-agent-container/v3 is accepted. Older apiVersions (v1, v2) raise loud validation errors — no backward compatibility.

Return type:

AgentConfig

scitex_agent_container.config.resolve_config(name_or_path)[source]

Resolve agent name or path to a config file path.

Return type:

str

Search order for short names (no slash, no .yaml/.yml suffix):
  1. Project-local — first .scitex/agent-container/agents/ found walking upward from cwd. Highest priority so checked-in test agents and CI fixtures override globals.

  2. ~/.scitex/agent-container/agents/<name>.yaml (sac install root)

  3. $SCITEX_AGENT_CONTAINER_YAML_DIRS (colon-separated extra dirs)

  4. Fleet layout — for each root in (~/.scitex/orochi, ~/.dotfiles/src/.scitex/orochi):

    1. <root>/<HOST>/agents/<name>/<name>.yaml (host override)

    2. <root>/shared/agents/<name>/<name>.yaml (shared default)

Pass an explicit path (with / or .yaml/.yml) to bypass the search entirely.

scitex_agent_container.config.resolve_hostname()[source]

Return the canonical host label for this machine.

Return type:

str

Resolution order (first non-empty wins):
  1. SCITEX_AGENT_CONTAINER_HOSTNAME env var (manual override).

  2. SCITEX_OROCHI_HOSTNAME env var.

  3. hostname_aliases[short hostname] from shared/config.yaml or ~/.scitex/agent-container/config.yaml.

  4. socket.gethostname() short form (identity fallback).

Raises:

RuntimeError – If none of the sources produces a non-empty value. This should be practically impossible (gethostname() returns something on any configured box) but is handled loudly rather than returning the empty string.

scitex_agent_container.config.substitute_hostnames(obj, hostname=None)[source]

Recursively walk a dict/list/str and substitute hostname placeholders.

Non-string leaves (int, bool, None) are returned unchanged. The walk is pure-functional — the input is not mutated; a new structure is returned.

Parameters:
  • obj (Any) – YAML-parsed structure (dict/list/scalar).

  • hostname (str | None) – Override hostname (for tests). If None, calls resolve_hostname().

Return type:

Any

scitex_agent_container.config.validate_config(path)[source]

Validate a config file and return list of errors (empty = valid).

Return type:

list[str]

scitex_agent_container.config.validate_contributor_spec(path)[source]

Validate a contributor spec YAML file. Returns list of errors (empty = valid).

Return type:

list[str]

scitex_agent_container.config.validate_contributor_spec_raw(raw, path='<unknown>')[source]

Validate a contributor spec dict. Returns list of error strings.

Return type:

list[str]

Lifecycle

Registry

Observability

Pane Actions

Runtimes / Multiplexer

Multiplexer abstraction — dispatches to screen or tmux.

class scitex_agent_container.runtimes.multiplexer.MultiplexerProtocol(*args, **kwargs)[source]

Bases: Protocol

Common interface for screen/tmux managers.

static exists(session_name)[source]
Return type:

bool

static start(session_name, command, workdir, env_exports='', venv='')[source]
Return type:

bool

static stop(session_name)[source]
Return type:

bool

static capture_content(session_name)[source]
Return type:

str

static capture_logs(session_name, lines=50)[source]
Return type:

str

static send_keys(session_name, *keys)[source]
Return type:

None

static send_text_and_submit(session_name, text)[source]
Return type:

None

static attach(session_name)[source]
Return type:

None

__init__(*args, **kwargs)
scitex_agent_container.runtimes.multiplexer.get_multiplexer(config)[source]

Return the appropriate multiplexer class based on config.

Return type:

type

Modular TUI prompt detection and response for Claude Code.

Each prompt handler defines: - name: identifier for logging - detect(content) -> bool: whether this prompt is visible - respond(send_keys) -> None: keystrokes to accept the prompt - priority: lower = checked first (default 10)

Add new handlers by appending to PROMPT_HANDLERS or calling register_prompt().

class scitex_agent_container.runtimes.prompts.PromptHandler(name, detect, keys=<factory>, priority=10)[source]

Bases: object

A single TUI prompt detector and responder.

name: str
detect: Callable[[str], bool]
keys: list[str]
priority: int = 10
__init__(name, detect, keys=<factory>, priority=10)
scitex_agent_container.runtimes.prompts._detect_bypass_permissions(content)[source]

Bypass Permissions mode prompt with radio selector.

Return type:

bool

Matches:

“1. No, exit” “2. Yes, I accept” “Bypass Permissions” “Enter to confirm”

scitex_agent_container.runtimes.prompts._detect_dev_channels(content)[source]

Development channels loading confirmation.

Return type:

bool

Matches:

“1. I am using this for local development” “2. Exit” “development channels” or “dangerously-load-development-channels” “Enter to confirm”

scitex_agent_container.runtimes.prompts._detect_thinking_effort(content)[source]

Thinking effort level selector.

Return type:

bool

Matches:

“1. * Medium (recommended)” or similar “thinking” in various casings “Enter to confirm”

scitex_agent_container.runtimes.prompts._detect_skip_permissions_yn(content)[source]

Legacy y/n text prompt for skip-permissions (older Claude Code).

Matches text-based y/n prompts without radio selector.

Return type:

bool

scitex_agent_container.runtimes.prompts._detect_mcp_json_edit(content)[source]

Permission prompt when Claude tries to edit .mcp.json (runtime).

Matches “1. Yes” / “1. Proceed” / “1. Allow” + “.mcp.json” + “Enter to confirm”.

Return type:

bool

scitex_agent_container.runtimes.prompts._detect_press_enter_continue(content)[source]

Generic ‘Press Enter to continue’ runtime pause (context-window warning, etc).

Uses a strict last-5-lines window to avoid scrollback false positives (per pane-state-patterns.md: classify against last 5 visible lines only). Excluded: active tool calls and numbered radio selectors.

Return type:

bool

scitex_agent_container.runtimes.prompts._detect_file_trust(content)[source]

‘Do you trust the files in this folder?’ prompt (first-run or new cwd).

May appear when –dangerously-skip-permissions was not propagated to a subshell. Matches the LEGACY y/n text variant; the new radio-selector variant is handled by _detect_file_trust_radio().

Return type:

bool

scitex_agent_container.runtimes.prompts._detect_file_trust_radio(content)[source]

Radio-selector variant of the file-trust prompt.

Claude Code (>= ~2.1.x) asks “Is this a project you created or one you trust?” with numbered options instead of the legacy y/n text prompt. Appears on the first launch in any un-trusted workdir — including every throwaway tempdir the Haiku integration test uses.

Matches the exact option strings to avoid firing on the bypass-permissions dialog (which also says “Enter to confirm”).

Return type:

bool

scitex_agent_container.runtimes.prompts._detect_external_imports(content)[source]

External CLAUDE.md file imports prompt.

Appears when CLAUDE.md (or .claude/CLAUDE.md) contains @<absolute-path> imports pointing OUTSIDE the agent’s workdir. Triggered by the at-import skill-injection mode (sac PR #74) when skills live in ~/.claude/skills/ or the package source trees rather than the workspace itself.

Return type:

bool

Matches:

“Allow external CLAUDE.md file imports?” “1. Yes, allow external imports” “Enter to confirm”

scitex_agent_container.runtimes.prompts._detect_login_method(content)[source]

First-run login-method picker on a fresh HOME.

Appears when Claude Code can’t find OAuth credentials at ~/.claude/.credentials.json. Even with ANTHROPIC_API_KEY set in env, the 2.1.x CLI still asks which auth mode to use before it checks the env var. Blocks startup until dismissed.

Matches the exact option strings to avoid false positives on any user message that happens to say “login method”.

Return type:

bool

scitex_agent_container.runtimes.prompts._detect_theme_selection(content)[source]

First-run theme selection prompt.

Appears only on a fresh HOME (no ~/.claude/ saved theme). On dev machines it never shows, but in CI (a clean ubuntu VM) this is the first thing Claude Code asks. Blocks every downstream startup prompt until acknowledged.

Matches the radio variant: “Choose the text style…” + numbered options starting with “1. Auto (match terminal)”.

Return type:

bool

scitex_agent_container.runtimes.prompts._detect_compose_pending_unsent(content)[source]

Detect unsent text sitting in the Claude Code compose buffer.

The classifier in agent_meta._classify_pane_state matches ❯[ \t]+\S (non-whitespace after the prompt marker on the same line), meaning the user has typed something but not yet pressed Enter. We mirror that pattern here so the prompts system can submit it via a plain Enter keystroke.

Excluded: lines that are just the decorative separator below an empty prompt — those contain only whitespace after .

Return type:

bool

scitex_agent_container.runtimes.prompts._detect_done(content)[source]

Check if claude is at the main input prompt (all TUI prompts done).

The status bar shows “bypass permissions” when ready.

Return type:

bool

scitex_agent_container.runtimes.prompts.register_prompt(handler)[source]

Add a custom prompt handler to the registry.

Return type:

None

scitex_agent_container.runtimes.prompts.detect_and_respond(content, accepted, send_keys_fn)[source]

Check content against all handlers, respond to the first match.

Parameters:
  • content (str) – Captured pane content.

  • accepted (set[str]) – Set of already-accepted prompt names.

  • send_keys_fn (Callable[..., None]) – Callable to send keystrokes (e.g., mux.send_keys).

Return type:

str | None

Returns:

Name of the matched prompt, or None if no match.

scitex_agent_container.runtimes.prompts.is_ready(content)[source]

Check if claude is at the main input prompt (all TUI prompts done).

Return type:

bool