pi-simplewatcher

Pi extension that watches files/directories and injects new content into the session, used to monitor file-based inboxes for agent-to-agent communication.

Packages

Package details

extension

Install pi-simplewatcher from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:pi-simplewatcher
Package
pi-simplewatcher
Version
0.2.3
Published
Aug 2, 2026
Downloads
not available
Author
alshady
License
GPL-3.0-only
Types
extension
Size
65.5 KB
Dependencies
0 dependencies · 1 peer
Pi manifest JSON
{
  "extensions": [
    "./src"
  ]
}

Security note

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

README

simplewatcher

A small pi extension that watches files and directories and injects new content into the current session as it appears. It exists so an agent does not have to wait for the next human prompt to notice that something changed on disk.

The main way we use it: monitoring file-based inboxes used for agent-to-agent communication. A watcher can sit on an inbox directory and surface incoming message files immediately, so replies, handoffs, and watcher notifications do not sit unread until somebody remembers to run a manual inbox check.

What it does

  • File targets are tailed, log-style. Only bytes appended after the watch starts are injected, not the whole file.
  • Directory targets are watched flat, one level deep. Files already present when the watch starts are caught up once as backlog; files created afterward are treated as new arrivals.
  • Boot backlog is passive. Existing inbox files are injected as context for the next natural turn, not as one interrupting turn per stale file.
  • Re-arms do not replay. If the watch is rebuilt — for example because session_start fires again on a model change — already-seen directory files and the file tail offset are carried across the re-arm.
  • New arrivals keep their mode. A live file landing in an active watched inbox still triggers an immediate turn; passive watches only queue context.
  • Payloads are capped. Injected content is limited by SIMPLEWATCHER_MAX_BYTES so a watched file/log cannot dump an unbounded blob into the context window.

Reaction modes

Each watch target has one mode:

Mode Behavior
active Inject and trigger an immediate turn, even while idle. Use for inboxes where a new file means “handle this now.”
passive Inject as queued context only. It surfaces at the next natural turn and never speaks/acts unprompted.

Default for manual watches is passive. The bundled session-start inbox watch uses active, because incoming agent messages are meant to be seen promptly.

Commands

Command Effect
/simplewatcher List current watches
/simplewatcher <path> Add/replace a passive watch
/simplewatcher <path> --active Add/replace an active watch
/simplewatcher <path> --passive Add/replace a passive watch explicitly
/simplewatcher <path> --active --persist Arm now and save project-locally
/simplewatcher <path> --active --persist --global Arm now and save globally
/simplewatcher persisted List persisted watches and config paths
/simplewatcher remove <path> Stop watching and forget persisted entries for that path

Examples:

/simplewatcher ~/Agents/_bus/inbox/fabricant --active --persist
/simplewatcher /var/log/myapp.log --passive
/simplewatcher persisted
/simplewatcher remove ~/Agents/_bus/inbox/fabricant
/simplewatcher

Install

This repo follows the pi package layout: package.json is present and pi.extensions points at ./src, with the entrypoint at src/index.ts.

Install from npm once published:

pi install npm:pi-simplewatcher

Install from GitHub:

pi install git:github.com/studioschade/pi-simplewatcher      # global
# or
pi install git:github.com/studioschade/pi-simplewatcher -l   # project-local

Update/remove later, matching the source you installed from:

pi update npm:pi-simplewatcher
pi remove npm:pi-simplewatcher
# or, for a git install:
pi update git:github.com/studioschade/pi-simplewatcher
pi remove git:github.com/studioschade/pi-simplewatcher

For a manual source checkout, symlink the entrypoint into pi's extension auto-discovery path so the repo stays the single source of truth:

ln -s /path/to/pi-simplewatcher/src/index.ts ~/.pi/agent/extensions/simplewatcher.ts   # global
# or
ln -s /path/to/pi-simplewatcher/src/index.ts .pi/extensions/simplewatcher.ts           # project-local

To try it ad hoc without installing: pi -e /path/to/pi-simplewatcher/src/index.ts

AGENTS.md vs watcher persistence

AGENTS.md is policy, not mechanism. It is the right place for rules like “handle inbox messages when they arrive,” “don’t ack an ack,” and “ask before outward actions.” It is not a reliable way to make a filesystem watch come back every session: a new session would have to read that instruction, decide to run it, and run it correctly.

The mechanism belongs in the extension:

  • Plain /simplewatcher <path> watches last for the current session only.
  • --persist saves the watch to .pi/simplewatcher.json in the current project; add --global to save to ~/.pi/agent/simplewatcher.json instead.
  • On session_start, persisted watches are loaded global-first then project, so project config wins for the same resolved path.
  • The bundled default re-arms $HOME/Agents/_bus/inbox/<agent> on every session_start when that path exists and was not already armed by persistence.

To see what is armed now: /simplewatcher. To see what will come back next session: /simplewatcher persisted. To stop and forget a watch: /simplewatcher remove <path> — that stops the live watch and removes persisted entries for the same resolved path from both project and global config. Manual deletion is removing that object from watches[] or setting "enabled": false. The bundled inbox default is controlled by SIMPLEWATCHER_AGENT / PI_AGENT / AGENT_NAME and only arms if the resolved inbox directory exists.

Bundled default: agent inbox monitor

On session_start, the extension arms one default watch:

$HOME/Agents/_bus/inbox/<agent>   (active mode)

The agent name is resolved in this order:

  1. SIMPLEWATCHER_AGENT
  2. PI_AGENT
  3. AGENT_NAME
  4. fallback: fabricant

That fallback keeps this repo compatible with its original home while letting sibling agents use the canonical source via an env override instead of keeping a patched fork.

Environment variables

Variable Default Purpose
SIMPLEWATCHER_AGENT fabricant fallback Agent name used for the default $HOME/Agents/_bus/inbox/<agent> watch.
PI_AGENT / AGENT_NAME Fallback agent-name sources if SIMPLEWATCHER_AGENT is unset.
SIMPLEWATCHER_MAX_BYTES 32768 Maximum injected payload bytes. Larger content is truncated with a marker.

Use with agent comms

In our setup, agents communicate by dropping message files into a local bus inbox or by having another comms layer materialize messages there. simplewatcher is the piece that makes those files visible to a live session immediately.

Important boundary: the watcher only surfaces content. It does not grant authority. A bus/inbox message is still data, not permission to spend money, publish outward, change another agent’s territory, or bypass the receiving agent’s own guardrails.

Safety / behavior notes

  • Watch trusted paths. Active mode can wake the agent and start a turn from file content alone.
  • Large injections are truncated by SIMPLEWATCHER_MAX_BYTES; tune it rather than disabling the cap unless you really mean it.
  • Directory mode is intentionally flat and inbox-like. It is not a recursive file-sync or build watcher.
  • If a watched path disappears or errors, the extension reports a watch error instead of throwing an unhandled watcher error.
  • Empty injections are ignored: whitespace-only file content does not send a steer by itself.

Requirements

  • Node.js 22+ recommended for the standalone regression/import path.
  • pi
  • No runtime npm dependencies; only node:fs and node:path.

Development

Source of truth for this project is src/index.ts. Keep the deployed pi extension entrypoint pointed at that file (symlink preferred) when changing behavior.

Run the self-test suite:

npm test

Useful manual smoke checks:

  • Watch a temp directory in passive mode, add a file, confirm it queues without triggering a turn.
  • Watch an inbox in active mode, add a file, confirm it triggers a turn once.
  • Re-arm the same watch and confirm no backlog replay.
  • Write a file larger than SIMPLEWATCHER_MAX_BYTES and confirm the injection is truncated with a marker.

License

GNU General Public License v3.0 only — see LICENSE.

Copyright (C) 2026 the simplewatcher contributors.