Skip to content

feat(agenthook): report Pi sessions so hosts can resume them - #161

Merged
wesm merged 15 commits into
mainfrom
pr/agenthook-pi
Oct 11, 2026
Merged

wesm merged 15 commits into
mainfrom
pr/agenthook-pi

Conversation

@rodboev

@rodboev rodboev commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

A Pi conversation now comes back after a restart. Tools that install agenthook hooks, such as Forge, get Pi's session ID and reopen it with pi --session <id>. Pi has no command-hook config, so install writes one extension module, extensions/agenthook.js, that runs every application's commands without a shell. It needs Pi 0.80.4 or later.

The module reports only from Pi's terminal UI, and only after Pi saves the session file, so each reported ID resumes from the project it started in. SessionEnd fires only when another session replaces the current one, so quitting leaves the session resumable. A root index.ts, index.js or package.json extension list stops Pi loading the module.

Refs kenn-io/forge#1282, slice 11 (Resume Pi agents)

@roborev-ci

roborev-ci Bot commented Oct 6, 2026

Copy link
Copy Markdown

roborev: Combined Review (477efad)

Verdict: Changes require fixes for 1 finding.

Medium

  • agenthook/script.go:34: Install writes agenthook.js and reports success when the Pi extensions directory has a root index.ts, index.js, or package.json pi.extensions configuration that prevents discovery of agenthook.js. This documented limitation leaves installed hooks silently inactive because installation does not check for these blockers.

    Fix: Detect directory entry points and manifest configuration that prevent discovery before installing, and return an actionable error. Add behavioral tests confirming blocked installations leave files unchanged.


Reviewers: 2x codex, codex (security) | Synthesis: codex, 8s | Total: 2m38s

@roborev-ci

roborev-ci Bot commented Oct 6, 2026

Copy link
Copy Markdown

roborev: Combined Review (865f5c1)

Verdict: No findings at or above medium severity.


Reviewers: 2x codex, codex (security) | Synthesis: codex | Total: 1m50s

@roborev-ci

roborev-ci Bot commented Oct 6, 2026

Copy link
Copy Markdown

roborev: Combined Review (1127390)

Verdict: No findings at or above medium severity.


Reviewers: 2x codex, codex (security) | Synthesis: codex | Total: 1m34s

@roborev-ci

roborev-ci Bot commented Oct 6, 2026

Copy link
Copy Markdown

roborev: Combined Review (e83b47e)

Verdict: No findings at or above medium severity.


Reviewers: 2x codex, codex (security) | Synthesis: codex | Total: 1m50s

@rodboev
rodboev marked this pull request as draft October 7, 2026 03:28
@rodboev rodboev self-assigned this Oct 7, 2026
@roborev-ci

roborev-ci Bot commented Oct 7, 2026

Copy link
Copy Markdown

roborev: Combined Review (0122104)

Verdict: No findings at or above medium severity.


Reviewers: 2x codex, codex (security) | Synthesis: codex | Total: 1m25s

@rodboev
rodboev marked this pull request as ready for review October 7, 2026 03:40
@rodboev
rodboev requested a review from wesm October 7, 2026 03:40
@mariusvniekerk
mariusvniekerk added this pull request to stack #175 October 9, 2026 13:43
@wesm wesm self-assigned this Oct 10, 2026
A host that reopens a Pi session with pi --session needs to know the
session was resumed. Pi reports startup for every first launch, even when
it opens a saved session. Claude Code reports resume in the same case, so
hosts got a different answer from Pi. A saved session file at startup
means Pi opened an existing session, so the module now reports resume.

A failed hook showed only its exit status in Pi. The command's own error
text was lost, so a user had nothing to act on. Failures now end with the
tail of the command's stderr. Reading stderr adds a risk: a background
process that the hook starts can inherit the pipe and keep it open. The
module stops waiting shortly after the command exits, and keeps reading
the pipe so that process never blocks and Pi is not held open.

After the last application uninstalled, Pi kept loading an empty module
on every start. The file belongs only to kit, so Uninstall now deletes it.
Result.Data is nil in that case, so callers that dump the planned config
can tell a deletion from a rewrite.

PI_CODING_AGENT_DIR also accepts file URLs, as Pi's own path handling
does. Kit used to treat such a URL as a relative path and installed the
module where Pi never looks.

The Pi source links now point to a fixed commit, so their line ranges stay
correct as Pi changes.

Generated with Claude Code (claude-opus-5-5)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@roborev-ci

roborev-ci Bot commented Oct 10, 2026

Copy link
Copy Markdown

roborev: Combined Review (a426d78)

Verdict: Changes require fixes for 3 findings.

High

  • agenthook/agenthook_test.go:1337: The post-run FileExists loop checks files the driver unconditionally created and cannot detect reporting before persistence. The existing nothingSent checkpoint and report comparison already cover the relevant behavior.

    Fix: Remove the post-run FileExists loop; retain the event-time nothingSent checkpoint and expected report comparison.

Medium

  • agenthook/script_runtime.js:54: The execution timeout remains armed during the post-exit stderr grace period, so a hook that exits successfully shortly before its deadline can incorrectly be reported as timed out while a descendant holds stderr open.

    Fix: Clear the execution timeout when the exit event arrives, before starting the bounded stderr grace period. Add coverage for successful pre-deadline exit with inherited stderr.

  • agenthook/pi.go:105: File-URL conversion omits Node's authority normalization: file://LOCALHOST/tmp/pi is rejected on Unix, and file://C:/Users/me/pi becomes an invalid UNC path on Windows, breaking hook installation and removal.

    Fix: Apply WHATWG authority normalization before conversion, including case-insensitive localhost handling and drive-letter authorities. Add config-path regression tests for both cases.


Reviewers: 3x codex, codex (security) | Synthesis: codex, 11s | Total: 8m29s

A hook that finished just before its timeout could still be reported as
timed out. This happened when a background process it started kept its
stderr open: the deadline stayed armed while the extension waited a short
time for stderr to close. The deadline now stops when the command exits.
No test covers this window. It needs a command to exit within 250ms of its
deadline, and process start time on CI runners varies by more than that.

Kit read some PI_CODING_AGENT_DIR file URLs differently from Pi. Node,
which Pi runs on, lowercases the host, so file://LOCALHOST is a local
path. Node also reads file://C:/ as drive C, where Go reads C: as a host.
In those cases kit installed the module in a directory Pi never loads, or
refused a value that Pi accepts.

The Pi test no longer checks that each reported transcript exists. It ran
after the test had created every saved file, so it could not catch an
early report, and the exact report comparison already rejects any report
for a session that was never saved. The helper's background process now
starts in the test binary's directory instead of the system temp
directory, which the usetesting lint rejects in tests.

Generated with Claude Code (claude-opus-5-5)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@roborev-ci

roborev-ci Bot commented Oct 10, 2026

Copy link
Copy Markdown

roborev: Combined Review (e7900cc)

Verdict: No findings at or above medium severity.


Reviewers: 3x codex, codex (security) | Synthesis: codex, 6s | Total: 6m32s

@wesm
wesm merged commit 30552eb into main Oct 11, 2026
9 checks passed
@wesm
wesm deleted the pr/agenthook-pi branch October 11, 2026 01:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants