@lystran/pi-serena-hooks

Run Serena lifecycle hooks from Pi coding agent

Packages

Package details

extension

Install @lystran/pi-serena-hooks from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:@lystran/pi-serena-hooks
Package
@lystran/pi-serena-hooks
Version
0.2.1
Published
Sep 24, 2026
Downloads
1,038/mo · 79/wk
Author
lystran
License
MIT
Types
extension
Size
20.8 KB
Dependencies
0 dependencies · 1 peer
Pi manifest JSON
{
  "extensions": [
    "./src/index.ts"
  ]
}

Security note

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

README

@lystran/pi-serena-hooks

Connects Serena lifecycle commands to a Pi coding agent. The plugin injects JSON stdin into Serena hooks and uses Serena's claude-code hook format to match Pi's native tool events.

Prerequisites

  • Pi coding agent >=0.84.2
  • Node.js >=20
  • The Serena CLI is installed on the system
  • Both serena and serena-hooks are available on PATH
  • An MCP extension is installed and configured with the Serena MCP server

Verify the CLI installation before starting Pi:

serena --version
serena-hooks --help

Install Serena using the method documented by the Serena project: https://oraios.github.io/serena/

This plugin does not provide the Serena MCP server or install the Serena CLI. Configure Serena's MCP server through an MCP extension such as pi-mcp-adapter:

{
  "mcpServers": {
    "serena": {
      "command": "serena",
      "args": [
        "start-mcp-server",
        "--context=ide",
        "--project-from-cwd"
      ]
    }
  }
}

The MCP extension and this hooks plugin have separate responsibilities: the MCP extension exposes Serena's symbolic tools to Pi, while this plugin runs Serena's lifecycle and remind hooks.

Installation

pi install npm:@lystran/pi-serena-hooks

For local development:

cd plugins/serena-hooks
pi install -l .

Integrated Plugins

@ff-labs/pi-fff

The plugin supports all three FFF operating modes:

FFF mode Search tools handled by Serena
tools-and-ui ffgrep, optional fff-multi-grep
tools-only ffgrep, optional fff-multi-grep
override grep, optional multi_grep

FFF path-search tools, fffind and overridden find, are intentionally not sent to remind.

pi-mcp-adapter

This is the recommended MCP companion plugin for exposing Serena's symbolic tools to Pi. It is not intercepted by remind; configure the Serena MCP server and its direct tools through pi-mcp-adapter separately.

Serena Hook Format

The plugin is compatible with the JSON hook protocol exposed by Serena's --client claude-code option. It sends session_id, tool_name, and tool_input through stdin, then handles Serena's hookSpecificOutput response:

  • additionalContext is forwarded to the Pi agent, after correcting Serena's stale session-start instruction to call activate_project (see Session-start Activation Instruction)
  • permissionDecision: "deny" blocks the current matching tool call, and its permissionDecisionReason together with additionalContext becomes the blocked tool result the model reads
  • command failures, timeouts, and malformed output do not block Pi

Using the claude-code format does not require Claude Code and does not launch Claude Code. It only selects Serena's compatible hook input and output schema for this Pi adapter.

Session-start Activation Instruction

Serena's serena-hooks activate emits a session-start reminder that instructs the agent to call Serena's activate_project tool. That instruction is stale for the configuration this plugin documents.

Serena removes activate_project from its tool list when the MCP server is started with a context that uses single-project mode and a project is supplied at startup — for example --context=ide --project-from-cwd, the configuration shown above. In that case the project is already active and project switching is not allowed, so the tool does not exist at all. An agent that follows the reminder calls a non-existent tool, and may then spend turns searching for it instead of doing the task.

The plugin therefore rewrites only that clause into a conditional form:

  1. if Serena's activate_project tool is available, activate it unless already done.

Everything else in the reminder is forwarded byte for byte. This keeps the reminder correct under both configurations: with auto-activation the clause is skipped, and without it the agent is still told to activate the project. If a future Serena release fixes the upstream wording, the pattern no longer matches and the text passes through unchanged.

Lifecycle Mapping

Pi event Command
Any session_start serena-hooks activate --client claude-code
A session_tree navigation that rewinds the branch to before the first user message serena-hooks activate --client claude-code again
Before a model code-search call serena-hooks remind --client claude-code
session_shutdown with reason quit, new, resume, or fork serena-hooks cleanup --client claude-code

activate context is queued with deliverAs: "nextTurn", so it is injected into the same turn as the next user message rather than one turn later. Rewinding is detected by inspecting the branch after navigation: navigating to a user message moves the leaf to that message's parent, so a branch without any user message means the branch now starts before the first user message. A navigation that leaves the leaf unchanged, and any further navigation before the next user message, does not re-inject the context. session_shutdown with reason reload keeps the same session and therefore skips cleanup.

remind watches model-initiated grep, ffgrep, multi_grep, and fff-multi-grep tools, plus Bash calls whose command starts with grep, rg, fgrep, egrep, ag, or ack. These calls are normalized to Serena's grep semantics, supporting Pi's native search tools and FFF's tools-and-ui, tools-only, and override modes. Ordinary Bash, skill reads, source reads, and documentation reads do not trigger the reminder. find and fffind search paths and do not trigger remind. Each command waits for at most 10 seconds. Missing commands, timeouts, and non-zero exits do not block Pi; each action produces at most one warning per session, while later events continue to attempt the command.

Shell commands executed directly by the user with ! or !! do not trigger remind.