@stevensuna/pi-interactive-agents

Interactive agent runtime for the Watcher control plane

Packages

Package details

extension

Install @stevensuna/pi-interactive-agents from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:@stevensuna/pi-interactive-agents
Package
@stevensuna/pi-interactive-agents
Version
3.8.2
Published
Jun 18, 2026
Downloads
not available
Author
stevensuna
License
MIT
Types
extension
Size
225.2 KB
Dependencies
0 dependencies · 3 peers
Pi manifest JSON
{
  "extensions": [
    "./pi-extension/workers/index.ts"
  ]
}

Security note

Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.

README

@stevensuna/pi-interactive-agents

Product: Nexium Pi interactive worker runtime. npm scope is @stevensuna until the nexiumlab org exists on npm — see docs/NPM_SCOPE.md.

Interactive agent runtime for the Watcher control plane.

This package is a Pi extension that lets Watcher spawn and supervise fixed-role workers in cmux, tmux, zellij, or WezTerm panes. Watcher remains the sole control plane: lifecycle tools are registered only when WATCHER_PARENT=1.

Public Tools

Parent-only lifecycle tools:

Tool Purpose
watcher_worker_spawn Spawn a fixed-role worker in a dedicated multiplexer pane
watcher_worker_interrupt Send Escape to a running Pi-backed worker turn
watcher_workers_list List running workers and available role definitions
watcher_worker_resume Resume a prior worker session in a new pane

Child-only worker tools:

Tool Purpose
worker_ping Ask Watcher for help and exit the worker session
worker_done Mark worker completion and exit the worker session

No slash commands are registered. Watcher drives orchestration through tools.

Roles

Bundled roles live in workers/:

Role CLI Model Auto-exit Interactive
scanner agy agy/gemini-3.5-flash yes yes
generator codex gpt-5.5 yes no
generator-fallback grok grok-composer-2.5-fast yes no
evaluator claude claude/opus yes no
planner claude claude/opus no yes
researcher pi grok-cli/grok-4.3 yes no
browser agy agy/gemini-3.5-flash yes yes

Role model mappings are enforced. Bundled roles default to their native CLI launchers; explicit Pi-backed overrides still fail fast unless the role/model pair is known launchable by this runtime. Set WATCHER_ALLOW_MODEL_OVERRIDE=1 only for development/testing overrides.

Launch UX

Watcher workers are intended to be spawned from an interactive Pi parent session. A non-interactive parent such as pi -p ... can still execute tools, but it may not keep the live Workers status renderer visible above the editor.

Native workers default to the trusted local launch form with the most reliable completion path for that CLI. Watcher writes the prompt to context/<worker>.md, prints a small human banner, then launches the native CLI in the worker pane with auto-approve permissions:

Role Expected command shape
scanner `printf 'Watcher worker:
generator `printf 'Watcher worker:
generator-fallback `printf 'Watcher worker:
evaluator `printf 'Watcher worker:
planner `printf 'Watcher worker:

Native roles prefer interactive/TUI launches for pane-oriented work. Codex and Claude have lifecycle hooks that write ${WATCHER_WORKER_SESSION}.exit; bundled Agy scanner and browser roles run as interactive CLI panes and complete through the WATCHER_COMPLETE: OK token/screen fallback, or the stable terminal tail fallback, unless/until Agy exposes a deterministic per-invocation Stop hook. Grok generator-fallback stays on grok --prompt-file by default because process exit is the deterministic completion path for that fallback. worker_result is delivered when a deterministic sidecar appears, the CLI process exits, or an interactive fallback completes. Preferred (Layer 1): lifecycle hooks write ${WATCHER_WORKER_SESSION}.exit; Codex workers receive an ephemeral -c hooks.Stop=... override for the Watcher Stop hook, and Claude workers use the bundled Claude Stop hook. Fallback (Layer 2): wrapper process exits write the same .exit sidecar. Debug fallback (Layer 3): screen scraping recognizes completion tokens (WATCHER_COMPLETE: OK, BROWSER_PROBE_OK, HOOK_TEST_*, or WATCHER_COMPLETION_TOKEN regex) only after the terminal tail is stable for two polls with no busy markers. Legacy (off by default): per-CLI UI heuristics only when WATCHER_LEGACY_UI_DETECTORS=1. By default, worker panes close after worker_result is delivered.

Set WATCHER_WORKER_INTERACTIVE_CLI=0 to force native headless forms for all native CLIs where available. In that mode agy uses --print, claude uses -p @<prompt-file>, codex uses codex exec, and Grok uses --prompt-file. WATCHER_WORKER_STREAM=1 can wrap supported headless CLIs through stream-native-cli.sh; streaming is off by default.

Worker Pane UX

Worker panes close after completion by default. Set WATCHER_WORKER_CLOSE_PANE=0 to keep panes open for inspection while debugging.

cmux creates the first worker in a worker pane and then opens later workers as new surfaces in that pane. tmux and WezTerm split the first worker to the right of the parent and stack later workers downward from the previous worker surface. Zellij keeps its tab-aware placement logic.

When running in cmux, Watcher updates the workspace sidebar with cmux set-status watcher_worker '<role> · <cli> · <state>' and cmux set-progress ... --label '<role> · <cli> · <state>' as activity files change. These updates are cosmetic; worker completion still comes from the .exit sidecar. cmux settings such as autoResumeAgentSessions, agent hibernation, and native agent integrations can coexist with Watcher panes, but Watcher should not depend on those mechanisms for completion; the sidecar remains the contract.

Environment

Primary Watcher env vars:

Variable Purpose
WATCHER_PARENT=1 Explicitly enable parent lifecycle tools
(default) Lifecycle tools on for non-worker Pi sessions; off when WATCHER_WORKER_ROLE / PI_SUBAGENT_AGENT is set
WATCHER_PARENT=0 Force-disable lifecycle tools on a parent session
WATCHER_DENY_TOOLS Comma-separated denied tool names
WATCHER_MUX_BACKEND Force cmux, tmux, zellij, or wezterm
WATCHER_WORKER_DIR Global worker config root
WATCHER_WORKER_* Worker identity/session/activity values passed to children
WATCHER_WORKER_CLOSE_PANE Close worker pane/surface on completion; default 1. Set 0 to keep panes open for inspection
WATCHER_WORKER_INTERACTIVE_CLI Use interactive native CLI mode where supported; default 1. Set 0 for retained headless native forms
WATCHER_WORKER_SHELL_READY_DELAY_MS Delay before sending launch command, default 500
WATCHER_WORKER_STREAM Override native headless CLI stream wrapper use; default 0
WATCHER_WIDGET_TICK_MS Above-editor Workers widget elapsed refresh, default 2000
WATCHER_ZELLIJ_MIN_COLUMNS Minimum columns for Zellij worker panes, default 50
WATCHER_ZELLIJ_MIN_ROWS Minimum rows for Zellij worker panes, default 10

Legacy PI_SUBAGENT_*, PI_DENY_TOOLS, PI_CODING_AGENT_DIR, and PI_SUBAGENT_ZELLIJ_MIN_COLUMNS/ROWS aliases are still read where needed for compatibility with existing Pi runtime paths.

Status delivery

Worker status is event-driven. On spawn/resume, Watcher creates and watches worker-activity/<worker-id>.json; Pi workers update it from extension hooks, and native CLI wrappers mark starting, active, and done phases through WATCHER_WORKER_ACTIVITY_FILE.

If a worker pane/tab is closed manually, supervision treats it as an error (Worker pane was closed before completion) and clears the Workers widget and cmux sidebar status when the last worker ends.

Completion is delivered by watching ${WATCHER_WORKER_SESSION}.exit, with Claude stop sentinels watched only for transcript-copy compatibility. A 5s terminal sentinel watchdog and completion-token screen contract remain fallbacks for missed filesystem events, explicitly interactive roles without lifecycle hooks, or abnormal process exits. Agy scanner/browser currently rely on the WATCHER_COMPLETE: OK token/screen fallback or stable terminal tail because Agy does not currently expose a deterministic per-invocation Stop hook equivalent to Codex -c hooks.Stop=.... Grok generator-fallback remains headless with --prompt-file so process exit stays deterministic for fallback generation. When a completion path fires, Watcher finalizes the activity file to phase: done before removing the worker from the running set.

Current limitation: if the parent Pi extension is reloaded or the parent session shuts down while a worker is mid-flight, the in-memory watcher is aborted and workers are not re-adopted automatically by scanning existing activity files. The worker pane may continue running, but automatic worker_result delivery requires the original supervising watcher to remain alive.

Session reuse rule of thumb: reuse watcher_worker_resume only when the prior session file still exists, the repo and task are still the same, and no reload or shutdown interrupted supervision. Spawn a new worker when the session file is gone, the task scope changed, or a reload interrupted the watcher. When reuse is not possible, prefer artifact handoff files over missing watcher session JSONL files.