Status and Hook Integration

scitex-agent-container ships a non-agentic status collector and a companion Claude Code hook ingestor. Together they let any downstream consumer observe what an agent is doing without adding code to the agent itself.

Rich Status

sac agents list <name> --json emits a dict suitable for dashboards or fleet monitors. It merges the registry entry with fields collected by agent_meta.collect_rich() and event_log.summarize().

sac agents list my-agent --json

Selected fields:

pane_text

Recent tmux capture-pane output, with secrets (sk-ant-*, wks_*, token/password key=value pairs) redacted in-place.

pane_state

Deterministic classifier over pane_text. One of running, idle_prompt, y_n_prompt, auth_error, compose_pending_unsent, limit_reached, unknown.

stuck_prompt_text

Last meaningful line when pane_state indicates a blocking prompt (e.g. a y/n question or an auth error).

claude_md / mcp_json

Workspace CLAUDE.md (truncated) and .mcp.json (with token-style values redacted) so downstream consumers do not need per-host filesystem access.

recent_tools / recent_prompts

Last N tool uses and user prompts drawn from the hook ring-buffer.

agent_calls / background_tasks

Sub-agent launches and Bash invocations with run_in_background=true.

tool_counts

{tool_name: count} over the window.

last_tool_at / last_tool_name

ISO timestamp and tool name of the newest pretool event in the ring buffer (any tool, e.g. Edit, Bash, mcp__orochi__send_message). Acts as a functional heartbeat: lets orchestrators distinguish “process alive” from “LLM actually producing tool calls” without any extra collection – the values are derived from the existing hook buffer.

last_mcp_tool_at / last_mcp_tool_name

Same as above, restricted to the newest pretool event whose tool name starts with mcp__. Serves as an MCP sidecar health probe – confirms the MCP route is flowing, not just local tools.

last_action_at / last_action_name

ISO timestamp and name of the most recent recorded action attempt. last_action_name is renamed from the original last_action so it does not collide with the orochi hub’s own last_action column.

last_action_outcome / last_action_elapsed_s

Outcome string (success, precondition_fail, send_error, completion_timeout, skipped_by_policy) and wall-clock duration of that last attempt. None / "" when no attempt exists.

action_counts

{action_name: count} rollup over the configured window from action_store.summarize().

p95_elapsed_s_by_action

{action_name: p95_seconds} latency headline per action, suitable for dashboards.

quota_5h_used_pct, quota_7d_used_pct, quota_*_reset_at

Claude usage (best-effort; cached between calls).

metrics

Host-level CPU / memory / load / disk (psutil).

All fields are best-effort. Any failure leaves the default value ("", 0, 0.0, []) rather than raising.

Claude Code Hook Integration

scitex-agent-container ingest-hook-event <kind> is designed to be called from Claude Code’s hook configuration. It reads the Claude Code hook payload from stdin and appends a compact JSON record to a per-agent ring-buffer at $XDG_DATA_HOME/.scitex/agent-container/events/<agent>.jsonl (capped at 500 lines).

Wire it into the agent workspace’s .claude/settings.local.json:

{
  "hooks": {
    "PreToolUse":       [{"matcher": "", "hooks": [
      {"type": "command", "command": "scitex-agent-container ingest-hook-event pretool"}
    ]}],
    "PostToolUse":      [{"matcher": "", "hooks": [
      {"type": "command", "command": "scitex-agent-container ingest-hook-event posttool"}
    ]}],
    "UserPromptSubmit": [{"matcher": "", "hooks": [
      {"type": "command", "command": "scitex-agent-container ingest-hook-event prompt"}
    ]}],
    "Stop":             [{"matcher": "", "hooks": [
      {"type": "command", "command": "scitex-agent-container ingest-hook-event stop"}
    ]}]
  }
}

Agent name resolution order:

  1. --agent <name> CLI flag

  2. SCITEX_OROCHI_AGENT env var

  3. CLAUDE_AGENT_ID env var

  4. basename of the current working directory

The handler is fail-closed: any error is swallowed so that a broken event log can never abort a tool call. For PreToolUse in particular, a non-zero exit from a hook aborts the tool use; this implementation always exits zero.

status --json reads the ring-buffer through event_log.summarize() to populate recent_tools, recent_prompts, agent_calls, background_tasks, and tool_counts.

Zero Coupling Design

scitex-agent-container has no knowledge of any particular downstream orchestrator (scitex-orochi, a custom hub, etc.). status --json emits a self-describing dict; consumers wrap it themselves. For example, scitex-orochi’s heartbeat-push command:

  1. Shells out to sac agents list <name> --json.

  2. Reshapes the payload into its own hub schema.

  3. POSTs to its /api/agents/register/ endpoint.

Keeping the library decoupled from the orchestrator lets you swap the transport, the schema, or the orchestrator without touching this package.