pi-subagent-timeout-safety

extension

Mutation-safe timeout policy for pi-subagents launches

by · v0.3.0 · published 1w ago

$ pi install npm:pi-subagent-timeout-safety
downloads/mo
144
stars
last push
open issues

Signals

license: MITtestspi manifest: missinginstall size: —deps: 0peer deps: 0

Download trend

144 downloads · last 12 weeks (weekly)

README

pi-subagent-timeout-safety

A reusable Pi package that prevents a pi-subagents writer from being killed by a caller-supplied wall-clock timeout or turn budget while it may be in the middle of a file mutation.

It was originally designed against Pi 0.82.0 and pi-subagents 0.35.1. The current deployed compatibility matrix has also been verified with:

  • Pi 0.82.1
  • pi-subagents 0.37.0
  • Node.js 24+

This is currently version 0.3.0 of the package.

Why

pi-subagents treats timeoutMs / maxRuntimeMs as a hard elapsed deadline. When it expires, its runner terminates the child process and then escalates to SIGKILL. A hard turnBudget can also terminate a child. Neither is a safe boundary for an active edit, write, or mutating bash command.

This package changes only the LLM-issued subagent tool-call path:

  • For a possibly mutating run it removes run-level timeoutMs, maxRuntimeMs, and turnBudget before the tool executes.
  • It appends a checkpoint instruction to concrete writer tasks.
  • It leaves limits intact only when the resolved agent is tool-restricted and cannot mutate; prompt wording alone cannot revoke an agent's tools.
  • Unknown agent names fail closed: they are treated as capable of mutation.
  • Agent discovery mirrors local user/project scope, configured extra user-agent directories, and nested agent directories before classifying a custom role; package-provided agent definitions are treated as unresolved and fail closed.
  • It emits a durable subagent-timeout-safety audit message whenever it removes a limit.

It does not patch pi-subagents files.

Install

Review the source before installing—Pi packages execute with your user account's full permissions.

Install from npm (recommended)

pi install npm:pi-subagent-timeout-safety

Update or remove the npm installation:

pi update npm:pi-subagent-timeout-safety
pi remove npm:pi-subagent-timeout-safety

For a project-local installation recorded in .pi/settings.json, add -l:

pi install -l npm:pi-subagent-timeout-safety

Use pi update npm:pi-subagent-timeout-safety to update the package; use pi remove -l npm:pi-subagent-timeout-safety to remove that project-local installation.

Test or develop from a local checkout

pi -e /absolute/path/to/pi-subagent-timeout-safety

Install globally from a local checkout

pi install /absolute/path/to/pi-subagent-timeout-safety

Git sources remain an option when you need a specific repository revision for development or debugging:

pi install git:gitlab.com/aloneio/pi-subagent-timeout-safety

Restart Pi or run /reload after changing the source/configuration.

To remove a globally installed local checkout:

pi remove /absolute/path/to/pi-subagent-timeout-safety

Configuration

The package default is stored next to the extension entrypoint. In this source checkout, the path is:

extensions/subagent-timeout-safety/config.json

When this whole package directory is auto-discovered under ~/.pi/agent/extensions/subagent-timeout-safety/, the resulting live path is:

~/.pi/agent/extensions/subagent-timeout-safety/extensions/subagent-timeout-safety/config.json
{
  "version": 1,
  "enabled": true,
  "allowExplicitMutationTimeout": false,
  "unknownAgentMayMutate": true
}

Keep allowExplicitMutationTimeout set to false. Setting it to true disables the protection for caller-supplied writer limits and reintroduces the risk of a child being killed during mutation. Also leave turnBudget unset in the pi-subagents global extension configuration: it is a downstream fallback outside this package's interception boundary.

Use /subagent-timeout-safety in Pi to see the active policy and scan local agent definitions for unsafe frontmatter defaults.

Operational model

For long writer work, detach the run and bound only the parent's wait:

subagent({
  agent: "worker",
  async: true,
  task: "Implement the requested change and report checkpoints."
});

subagent_wait({ id: "run-id", all: true, timeoutMs: 1_200_000 });

subagent_wait timing out stops waiting; it does not terminate the child. Use status, steer, interrupt, or stop when the supervising agent decides what should happen next.

Classification

The policy is intentionally capability-based rather than prompt-trust-based. A custom agent whose resolved declared tools are all read-only can retain caller limits. An agent that has write, edit, bash, or another unrecognized tool is mutation-capable even if its task says read-only or its acceptance role is read-only: text does not remove tool permissions. Built-in pi-subagents roles are conservatively considered mutation-capable because their shipped tool sets include bash, write, or edit. Unknown agent names fail closed.

Important limitations

This is a supported Pi tool_call interception, not a full replacement for pi-subagents timeout architecture.

  1. Covered: normal model-issued subagent(...) calls, including action: "schedule" at creation time.
  2. Not covered: direct internal invocation paths that do not execute the Pi subagent tool—currently slash-command bridges, extension-to-extension delegation, RPC spawn, a scheduled job firing later, and an authorized fanout child. These paths must not be given writer hard limits until the upstream plugin offers a checkpoint-safe policy at its executor boundary.
  3. Global defaults: pi-subagents falls back to a configured global turnBudget after this hook. Do not configure a global turnBudget while mutation-capable agents are enabled; this package cannot distinguish those downstream fallback limits. Similarly, do not set per-agent timeout or turn-budget defaults on mutation-capable roles.
  4. Agent defaults: pi-subagents resolves custom-agent timeoutMs and turnBudget frontmatter after Pi's tool_call hook. The command reports detected local frontmatter defaults, but package-supplied agent defaults are treated as unresolved/fail-closed.
  5. Other termination causes remain: explicit stop, parent/session abort, protocol-output safety limits, provider failure, OS failure, and system shutdown can still end a child.

Development and verification

npm test
npm run check

The tests use no network and do not launch an LLM. They cover policy classification, limit removal, local agent discovery/scope, package loading, child exclusion, and the extension handler's mutation of Pi's validated tool input.

Security and distribution

The package contains no credentials, provider settings, models, user agent profiles, session state, or unrelated global extensions. package.json marks @earendil-works/pi-coding-agent as a peer dependency, per Pi package guidance.

License

MIT. See LICENSE.