npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@anthill-tec/sandesh-pi

v0.4.3

Published

Sandesh verbs as Pi extension tools

Readme

@anthill-tec/sandesh-pi

A Pi extension that exposes Sandesh — a tiny, standalone, multi-project messaging system for cooperating agent/orchestrator sessions — as native Pi tools, plus a supervised wake watcher that re-enters the Pi session when mail arrives.

The extension is a thin shim: each tool shells out to the sandesh CLI via pi.exec. No messaging logic lives here — Sandesh-core stays Python.

Install

# from the npm registry (gallery package)
pi install npm:@anthill-tec/sandesh-pi

# local development (from a checkout of this repo)
pi install ./integrations/pi

Prerequisite — the sandesh CLI (≥ 0.4.2)

The extension calls the sandesh binary — CLI ≥ 0.4.2 is required (the tools speak the --format toon AXI envelope; an older CLI is refused at session start with a too-old notice). It is resolved from PATH, else run on demand via uvx --from sandesh-relay[migrate] sandesh. Install it via any of:

uv tool install sandesh-relay     # uv
pipx install sandesh-relay        # pipx
./install.sh                      # from a repo checkout
# or the AUR package on Arch

Verify: sandesh --version.

Environment

| Variable | Purpose | | -------------------- | ----------------------------------------------------------------------------------------- | | $SANDESH_PROJECT | the project the tools route to (the default project_id). | | $SANDESH_ADDRESS | this session's own Sandesh address (the default watcher address). | | $SANDESH_AUTOSTART | 1 → arm the wake watcher at session start (the pre-0.4.0 auto-arm; off by default). | | $SANDESH_BIN | dev/test override: run exactly this binary (no PATH lookup, no uvx fallback). |

Individual tools accept an explicit project_id that falls back to $SANDESH_PROJECT. The extension reads these from the process environment only and never reads .env — load the project's .env at the shell (e.g. direnv: an .envrc containing dotenv, then direnv allow). If ./.env assigns the identity but it is not exported, session start warns. With both identity vars set, session start injects a ≤ 12-line ambient status block (your address, listening state, unread count) so the agent knows its mailbox state before the first turn.

The tools (16)

| Tool | What it does | | ----------------------- | -------------------------------------------------------------------------------- | | sandesh_setup | provision a project (idempotent). | | sandesh_register | add an address to the project's addressbook. | | sandesh_unregister | remove (soft-delete) an address; stops this session's own watcher for it first, and a live watcher elsewhere is tombstoned and waited for up to two poll intervals. | | sandesh_addressbook | list the project's registered addresses. | | sandesh_send | send a message (subject, optional body, to/cc, kind). | | sandesh_reply | reply to a message (threads on the parent; subject defaults to Re: …). | | sandesh_inbox | list messages addressed to an address (filters, limit); with_body adds the listed rows' bodies without marking read (full uncut — pair with limit). | | sandesh_fetch | fetch + mark-read messages for an address (full for bodies). | | sandesh_thread | walk the reply chain of a message; requester (your own address) returns the bodies of messages you sent or received, else they are counted as withheld (full uncut). | | sandesh_archive | archive a project (read-only, reversible; dry_run). | | sandesh_unarchive | restore an archived project to active (dry_run). | | sandesh_search | FTS5 full-text search over subjects/bodies (limit); hits carry a snippet, fields selects columns. | | sandesh_status | home view: address, listening, unread — plus watcher: running\|stopped. | | sandesh_notify_start | start the supervised wake watcher for an address (idempotent, one per address); returns the watcher table. A new watcher that exits within 2 s (e.g. an unregistered address) returns ok:false with the exit code and reason. | | sandesh_notify_status | list in-session watchers: address, running, last exit by default; project scopes the list, and is required when watchers span projects; fields selects watcher columns. | | sandesh_notify_stop | stop one watcher by address or an aggregate scoped by project; unscoped multi-project stops return an error. |

Results are AXI envelopes (--format toon)

Every tool returns the CLI's machine-readable AXI envelope in TOON encoding — the same text the CLI prints with --format toon (verb, ok, per-verb fields, help[], warnings[]). Shape knobs: fields: ["a","b"] selects columns (--fields a,b), full: true includes complete message bodies on fetch/thread (--full), and limit: N caps inbox/search (--limit N). Omitted knobs add no flag. Errors are results, not throws: a CLI failure that still emits an envelope comes back as ok: false with error and help[], so the agent can read and recover; only an undecodable failure (no envelope on stdout) throws with the verb, exit code and stderr. Every CLI call (tool verbs, --version probes, init --check; never the notify watcher) times out after 240 s; a timeout throws sandesh <verb> timed out after 240s, a cancelled call throws sandesh <verb> aborted.

Wake

A Pi extension cannot, by itself, re-enter a sleeping session. The extension runs the blocking sandesh notify watcher as a supervised child; when mail addressed to the watched address arrives, the watcher exits with the unread ids and the extension injects a follow-up turn (sendUserMessage(…, { deliverAs: "followUp" })) naming them. The agent fetches and acts; the supervisor relaunches the watcher.

The wake is tool-started (0.4.0): call sandesh_notify_start (defaults to $SANDESH_ADDRESS / $SANDESH_PROJECT), or set SANDESH_AUTOSTART=1 to keep the pre-0.4.0 auto-arm at session start (both identity vars must then be set). Supervision rules:

  • Exit 0 (mail) → one follow-up turn naming the ids, then an immediate relaunch.
  • Same ids again (nothing fetched yet) → no repeat message; relaunch delayed 30 s.
  • Exit 2 (timeout) → silent relaunch; 3 timeouts within 60 s surface one warning.
  • Exit 5 (already running elsewhere) → one quiet retry after 30 s (the other owner may be a previous watcher still winding down; the entry stays running); a second exit 5 in a row stops the loop quietly.
  • Exit 1 / 3 (tombstoned) / 4 (evicted) / killed by signal → the loop stops and a notice carries the code and the envelope's error.
  • One watcher per address: a second start for the same address returns already: true and spawns nothing; different addresses run concurrently. After a stop, a start for the same address is accepted at once but spawns its child only when the stopped one has exited, so it never loses the address to it.
  • Exit at start → sandesh_notify_start waits up to 2 s for a new watcher; if it exits in that window (e.g. an unregistered address) the call returns ok:false with the exit code and the envelope's error instead of ok:true.
  • Watchers belong to the Pi session that started them. A sub-agent session loads the extension again but never stops, takes over or reads the parent's watchers (nor routes their notices to its own UI); only the owning session's session_shutdown stops them.
  • A stop nobody requested (anything but sandesh_notify_stop, /sandesh-watcher stop or session_shutdown) still stops the watcher, but posts a warning naming the address and sandesh_notify_start so the wake is not lost silently.

Inspect or stop from the prompt with /sandesh-watcher status [--project <id>] and /sandesh-watcher stop [address] [--project <id>]; mixed-project aggregates require the project filter. sandesh_notify_status / sandesh_notify_stop are the tool equivalents.

Manual end-to-end smoke test

  1. Pick a project, e.g. Demo, and provision it plus two addresses:

    sandesh setup --project Demo
    sandesh --project Demo register --address "Mainline - Demo" --kind mainline
    sandesh --project Demo register --address "Track 1 - Demo" --kind track
  2. Start a Pi session with the extension installed and the env vars set for one address:

    export SANDESH_PROJECT=Demo
    export SANDESH_ADDRESS="Track 1 - Demo"
    export SANDESH_AUTOSTART=1   # or call sandesh_notify_start from inside the session
    pi
  3. From another terminal, send mail to the agent's address:

    sandesh --project Demo send --from "Mainline - Demo" --to "Track 1 - Demo" \
      --subject "ping"
  4. Confirm the Pi session wakes (a follow-up turn naming the message id is injected) and the agent fetches the message (sandesh_fetch shows the ping). The watcher then relaunches and waits for the next message; /sandesh-watcher status shows it running.

The automated counterpart is src/smoke.test.ts: it resolves the binary from $SANDESH_BIN → <repo>/.venv/bin/sandesh → PATH, runs every spawn under a temp XDG_DATA_HOME, and skips when the binary lacks --format.