Skip to content

feat(desktop): wire pi terminal agent to notification hooks#1

Closed
garritfra wants to merge 1 commit into
mainfrom
implement-superset-pi-hooks-prd
Closed

feat(desktop): wire pi terminal agent to notification hooks#1
garritfra wants to merge 1 commit into
mainfrom
implement-superset-pi-hooks-prd

Conversation

@garritfra
Copy link
Copy Markdown
Owner

Follow-up to superset-sh#2562, which added pi as a built-in agent (preset, command, icon, settings UI, docs). This PR adds the corresponding notification-hook integration in apps/desktop/src/main/lib/agent-setup/, so pi participates in the same Start/Stop/PostToolUse lifecycle that drives Superset's working indicator and completion chime for claude, codex, gemini, cursor, copilot, opencode, mastra, amp, and droid.

Mechanism

Ship a small TypeScript pi extension to the global pi extensions directory (~/.pi/agent/extensions/superset-hooks.ts). The extension subscribes to pi's lifecycle events and spawns notify.sh with Claude-Code-format hook_event_name JSON payloads, which the existing notify.sh dispatcher already speaks natively — no per-agent translator shim needed.

Install lifecycle: at desktop app launch, the new wrapper writes the extension using the standard writeFileIfChanged + signature-marker + version pattern. Pi's auto-discovery picks it up at the next session start. Install is unconditional on whether pi is installed — if pi is later installed via npm, hooks just start working.

Event mapping

pi lifecycle event emitted as Superset normalizes to
before_agent_start UserPromptSubmit Start
tool_execution_end PostToolUse PostToolUse (progress)
agent_end Stop Stop
session_shutdown Stop Stop (cleanup on Ctrl+C, SIGTERM, SIGHUP, /quit, /reload, /new, /resume, /fork)

Subagent filtering

Every event is gated on ctx.hasUI === false. Subagents spawned via the bundled subagent extension run via pi --mode json -p and have hasUI: false; user-facing interactive and RPC sessions have hasUI: true. The strict-equality check (rather than !ctx.hasUI) is intentional: pi versions older than 0.38.0 (where hasUI did not yet exist) still fire hooks correctly because undefined !== false. Subagent flicker is possible on those older versions only — documented limitation.

Structural symmetry

Identical to the opencode integration:

  • agent-wrappers-pi.ts — wrapper module exporting createPiExtension, getPiExtensionPath, getPiExtensionContent, PI_EXTENSION_MARKER
  • templates/pi-extension.template.ts — the extension itself, with // {{MARKER}} placeholder substituted at install time
  • agent-wrappers.ts — barrel re-export
  • desktop-agent-capabilities.ts — adds "pi-extension" action and { id: "pi", setupActions: ["pi-extension"] } target (no managedBinary — pi is user-installed via npm; cursor-agent is precedent)
  • desktop-agent-setup.ts — runners map entry

No changes required to notify.sh, the v2 host-service tRPC endpoint, the renderer event bus, or the server-side mapEventType.

Failure modes

All silent: notify.sh missing, spawn errors (EACCES/ENOENT), broken pipe, missing curl. Outside Superset (no SUPERSET_TERMINAL_ID/SUPERSET_TAB_ID/SUPERSET_PANE_ID set) the extension is a complete no-op.

Pi version compatibility

Soft minimum (not enforced): pi 0.31.0 introduced before_agent_start and session_shutdown; 0.38.0 introduced ctx.hasUI; 0.52.10 introduced tool_execution_end; 0.67.3 made session_shutdown fire on SIGHUP/SIGTERM. Pi's pi.on(eventName, handler) is permissive — unknown event names silently never fire. Extension degrades gracefully on older versions.

Tests

Three new it() blocks under describe("agent-wrappers pi", ...) in agent-wrappers.test.ts:

  1. getPiExtensionContent() returns a string containing PI_EXTENSION_MARKER (cleanup recognition).
  2. getPiExtensionContent() returns a string containing export default function (valid pi extension shape).
  3. createPiExtension() writes to ~/.pi/agent/extensions/superset-hooks.ts with marker present.

Local validation:

  • bun test apps/desktop/src/main/lib/agent-setup/agent-wrappers.test.ts → 29 pass / 0 fail
  • bunx biome check apps/desktop/src/main/lib/agent-setup/ biome.jsonc → clean
  • bun --filter='./apps/desktop' typecheck → exit 0
  • bun run lint (whole repo) → clean

End-to-end was smoke-tested against notify.sh during the design conversation: SUPERSET_DEBUG_HOOKS=1 echo '{"hook_event_name":"UserPromptSubmit"}' | ~/.superset/hooks/notify.sh returned HTTP 200 for all three managed event types (UserPromptSubmit, PostToolUse, Stop).

Out of scope (flagged for visibility)

Follow-up to superset-sh#2562, which added pi as a built-in agent (preset, command,
icon, settings UI, docs). This PR adds the corresponding notification-hook
integration in apps/desktop/src/main/lib/agent-setup/, so pi participates
in the same Start/Stop/PostToolUse lifecycle that drives Superset's
working indicator and completion chime for claude, codex, gemini, cursor,
copilot, opencode, mastra, amp, and droid.

Mechanism: ship a small TypeScript pi extension to the global pi
extensions directory (~/.pi/agent/extensions/superset-hooks.ts). The
extension subscribes to pi's lifecycle events and spawns notify.sh with
Claude-Code-format hook_event_name JSON payloads, which the existing
notify.sh dispatcher already speaks natively — no per-agent translator
shim needed.

Mapping:
  pi before_agent_start → UserPromptSubmit → Superset Start
  pi tool_execution_end → PostToolUse      → progress
  pi agent_end          → Stop             → completion / chime
  pi session_shutdown   → Stop             → cleanup on Ctrl+C, /quit, /reload

Subagent flicker is prevented by gating every event on ctx.hasUI === false
(strict equality, so older pi versions where hasUI is undefined still fire).

Structurally identical to the opencode integration: template file +
wrapper module + barrel re-export + capabilities target + runners map
entry. Mirrors writeFileIfChanged + signature/version marker convention.

No changes required to notify.sh, the v2 host-service tRPC endpoint, the
renderer event bus, or the server-side mapEventType.
@garritfra
Copy link
Copy Markdown
Owner Author

Re-targeting against upstream superset-sh/superset.

@garritfra garritfra closed this May 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant