@stevensuna/pi-interactive-agents
Interactive agent runtime for the Watcher control plane
Package details
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
@stevensunauntil thenexiumlaborg exists on npm — seedocs/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.