@sassywares/pi-extensions

A zesty power pack for pi: auto-titled sessions, real web access, clean handoffs, isolated subagents, and ask/work modes.

Packages

Package details

extension

Install @sassywares/pi-extensions from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:@sassywares/pi-extensions
Package
@sassywares/pi-extensions
Version
0.3.20
Published
Oct 22, 2026
Downloads
512/mo · 512/wk
Author
thekayshawn
License
MIT
Types
extension
Size
129.1 KB
Dependencies
0 dependencies · 3 peers
Pi manifest JSON
{
  "extensions": [
    "./extensions/auto-title.ts",
    "./extensions/web-search.ts",
    "./extensions/handoff.ts",
    "./extensions/subagent/index.ts",
    "./extensions/modes/index.ts"
  ]
}

Security note

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

README

Sassy Pi Extensions

A zesty power pack for pi — auto-titled sessions, real web access, clean handoffs, and isolated subagents. Install once, ship faster.

Sassy Pi Extensions is the Sassywares pi suite. It names each session from its first real turn, gives the agent web_search and web_fetch tools backed by Exa, carries context into a fresh session with /handoff, and runs bounded work in isolated subagents.

The package is @sassywares/pi-extensions; the repo is sassy-pi-extensions.

Contents

Why this suite

  • Zero config where it matters. Exa runs through its public MCP endpoint; titles use the model you are already talking to; /handoff uses the current session's model.
  • Native surfaces. Titles use pi's own session name, so they show up in the session picker, footer, and terminal title. Search, fetch, and subagents are ordinary tools the model can call.
  • Safe by default. web_fetch blocks localhost, private network addresses, and URLs with embedded credentials. Subagents run in isolated pi processes with the tools their agent file allows.
  • Opt out, not opt in. Auto-titling stops with one environment variable. Manual titles always win.
  • Composable with sassy-skills. sassy-cycle, sassy-debug, and sassy-handoff are built around the subagent and /handoff extensions.
  • Small. No background servers. Host-provided dependencies only.

Quick start

From a checkout (recommended — this also installs the agent definitions):

git clone https://github.com/sassywares/sassy-pi-extensions.git
./sassy-pi-extensions/scripts/install-agents.sh
pi install ./sassy-pi-extensions

Or install the package only:

pi install git:github.com/sassywares/sassy-pi-extensions@v0.3.0

Or from npm once published:

pi install npm:@sassywares/pi-extensions@0.3.0

A package-only install loads the extensions, but subagent has no agents until you link or copy some into ~/.pi/agent/agents/. Run scripts/install-agents.sh from a checkout to link the Sassy roster.

Reload pi (/reload) and confirm:

  • web_search and web_fetch are available to the model.
  • The session gets a title after the first assistant turn, and /title is registered.
  • /handoff is registered.
  • The subagent tool lists the Sassy agents.

To try the package without changing settings:

pi -e ./sassy-pi-extensions

Extensions

Extension Surface What it does
auto-title automatic + /title [text] Generates a short session title after the first meaningful turn. /title regenerates it; /title <text> sets one manually.
web-search web_search, web_fetch Searches the web via Exa and fetches readable page text with local-address protection.
handoff /handoff <goal> Summarizes the session into a continuation prompt and opens a fresh session with it in the editor for you to submit.
subagent subagent tool Runs single, parallel, or chained tasks in isolated pi processes and returns compact results.
modes alt+m, /ask, /work Ask mode removes the write tools and runs bash under an OS-level read-only sandbox. Work mode is pi as usual.

Auto-title

Runs after the first assistant turn that contains text. It builds a small transcript from the opening turns, asks the current model for a 2–6 word title, and writes it with pi.setSessionName().

  • Tries once per session. Use /title to retry after a provider failure.
  • Never overwrites a title you set manually.
  • Does not delay the turn; the title arrives when it is ready.
  • 15 second timeout, 32 output tokens, low temperature.
  • Titles are truncated to 60 characters.

Web search and fetch

web_search uses Exa's public MCP endpoint by default. Set EXA_API_KEY to use the direct Exa API instead (higher limits and your own quota).

web_fetch:

  • Accepts absolute http(s) URLs only.
  • Follows up to 5 redirects.
  • Blocks localhost, private/link-local addresses, and URLs with embedded credentials.
  • Accepts HTML and plain text, capped at 2 MB.
  • Screens the final URL after redirects, not just the first one.
  • Returns readable text, truncated to 50,000 characters (12,000 by default).

Handoff

/handoff <goal> generates a focused prompt for a new session, lets you edit it, then opens that session with the prompt seeded in the editor.

The extension uses the current session's model and the current conversation only. The new session cannot see the old one.

Subagent

The subagent tool spawns a separate pi process per invocation, so each task gets its own context window. Three modes:

  • single — { agent, task }
  • parallel — { tasks: [{ agent, task }, …] }
  • chain — { chain: [{ agent, task }, …] }, with {previous} replaced by the prior result

Agent definitions are Markdown files under ~/.pi/agent/agents/ and the nearest project .pi/agents/. Project agents override user agents with the same name.

This repo ships the Sassy roster:

Agent Role
scout Grounding scout: writes the shared grounding brief other agents read, including matching prior learnings from the project's .sassywares/config.yaml knowledge paths.
worker General-purpose implementation in an isolated context.
reviewer Quality, correctness, security, project-rule, and design-system review, diff-scoped.
validator Checks that the diff matches the plan, independent of review.

Link them with ./scripts/install-agents.sh. Edit the frontmatter to change each agent's model, thinking level, or tool allowlist.

Every subagent reads the same grounding brief instead of re-exploring the repo. See GROUNDING.md for its location, freshness check, and wait rule.

Parallel dispatch defaults to two concurrent subagents. A three-worker MiniMax M3.1 Flash batch showed stream stalls and request timeouts under load; DeepSeek Flash was fine with four. Raise the limit with PI_SUBAGENT_CONCURRENCY for a DeepSeek-only dispatch.

A watchdog kills a subagent when it emits no output for two minutes, which catches provider streams that hang after a partial response. Completed runs append one JSON line to ~/.pi/agent/subagent-runs.jsonl with model, thinking level, wall time, model time, tool time, turns, error turns, retries, token usage, cost, and the watchdog outcome. Use it to compare models instead of reconstructing runs from session files.

Modes

Two modes, toggled with alt+m or /ask and /work. Ask mode makes it safe to think out loud; work mode is pi as usual.

Ask mode enforces read-only access on two levels:

  1. Toolset. edit, write, codemode, subagent, and any other tool that can change files or run arbitrary code are removed from the model's active toolset, so it never sees them. A tool_call gate blocks them anyway, which also covers nested calls made by tools that stay active.
  2. Sandboxed bash. read, grep, find, ls, bash, web_search, and web_fetch stay available, because searching and reading is how the model answers honestly. Every bash command, including ! input, is wrapped in an OS-level sandbox that denies filesystem writes:
    • macOS: sandbox-exec with a deny file-write* profile.
    • Linux: bwrap with --ro-bind / /.

Writes do not fail quietly and they are not matched by pattern. rm, sed -i, tee, > redirection, git checkout, and a nested bash -c all fail at the OS level with Operation not permitted, while git log, git diff, rg, and network calls keep working. /dev and the temp directory stay writable so ordinary tools behave.

A backend is only trusted after it proves both halves of the contract: reads inside the working directory must succeed and a probe write there must fail. A backend that is installed but cannot enforce (for example bubblewrap on a distribution that blocks unprivileged user namespaces) is discarded, and ask mode continues without bash rather than falling back to a command allowlist. The working directory always wins over the temp allowance: if the project itself lives under the temp directory, temp writes are denied too and /modes reports temp dir is read-only.

/modes shows the verdict. While ask mode is active, the footer is replaced by a compact one that draws the badge on the working-directory/session line — ⏸ ask · ro(sandbox-exec) or ⏸ ask · bash off — instead of taking a row of its own; other extension statuses keep their line. Leaving ask mode restores pi's native footer.

  • --ask starts a session in ask mode; the mode persists across resume.
  • shift+tab is not used, because pi binds it to the thinking level. To match an editor that uses it for modes, bind app.thinking.cycle to something else in ~/.pi/agent/keybindings.json and add a shortcut there.
  • Ask mode is a guardrail for local changes, not a jail. Network access stays open, so a command can still change remote state if it holds a credential. Use pi's containerized setup when the boundary has to hold against a hostile model.
  • Windows is unsupported by design. Ask mode needs an OS-level read-only sandbox that Windows does not offer cheaply, so the extension registers nothing there. /ask and /work do not exist, and every tool behaves as before.

Configuration

Variable Default Effect
PI_AUTO_TITLE unset Set to 0 to disable automatic titles. /title still works.
EXA_API_KEY unset Use the direct Exa API instead of the public Exa MCP endpoint.
PI_AGENTS_DIR ~/.pi/agent/agents Target directory for scripts/install-agents.sh.
PI_MODES_BASH auto Set to off to skip backend detection. Ask mode then runs without bash.
PI_MODES_ASK_TOOLS unset Comma-separated extra tool names to allow in ask mode.
PI_SUBAGENT_CONCURRENCY 2 Maximum parallel subagent processes. DeepSeek Flash handled 4; MiniMax M3.1 Flash stalled with 3.
PI_SUBAGENT_IDLE_TIMEOUT_MS 120000 Kill a subagent after this many milliseconds with no stdout/stderr events. Set to 0 to disable.
PI_SUBAGENT_TELEMETRY ~/.pi/agent/subagent-runs.jsonl Telemetry JSONL path, or 0/off to disable.

Security

Extensions run inside the pi process with the same OS permissions as pi. Review extension source before installing it.

  • web_fetch is designed for public web pages, not for reaching services on your machine or local network.
  • auto-title sends a short transcript of the opening turns to the model already selected for the session. Provider terms and data handling apply.
  • /handoff sends the conversation and your goal to the current model to generate the continuation prompt.
  • subagent starts additional pi processes. Their permissions match the tools allowed by their agent file and the pi process that spawned them.
  • modes ask mode denies local filesystem writes through the OS sandbox described above. It does not restrict network access, so a sandboxed command can still change remote state if it can authenticate. Work mode has no restrictions.
  • No credentials are stored by this package. EXA_API_KEY is read from the environment at call time.

Provenance

handoff and subagent are derived from pi's MIT-licensed examples and documentation, modified for this workflow. See NOTICE.

Repository layout

sassy-pi-extensions/
├── extensions/
│   ├── auto-title.ts
│   ├── handoff.ts
│   ├── web-search.ts
│   ├── modes/
│   │   ├── backends.ts
│   │   └── index.ts
│   └── subagent/
│       ├── agents.ts
│       └── index.ts
├── agents/
│   └── *.md
├── scripts/
│   └── install-agents.sh
├── .github/workflows/
│   └── publish.yml
├── AGENTS.md
├── CONCEPTS.md
├── LICENSE
├── NOTICE
├── README.md
└── package.json

Development

This repo is the source of truth for the extensions and the Sassy agents. Install it locally so pi loads the working tree directly:

./scripts/install-agents.sh
pi install ~/Documents/Workspace/Sassywares/sassy-pi-extensions

Local installs are read in place — no copy, no build step. After changing an extension, run /reload in pi. Agent edits are picked up on the next subagent invocation.

Do not also keep copies under ~/.pi/agent/extensions/; pi would load both and register duplicate tools and commands.

Test the package for one invocation without touching settings:

pi -e ~/Documents/Workspace/Sassywares/sassy-pi-extensions

Manual checks after a change:

  • web_search with and without EXA_API_KEY.
  • web_fetch on a normal page, and on http://localhost:3000 (must be rejected).
  • /title, /title <text>, and automatic naming with PI_AUTO_TITLE unset.
  • PI_AUTO_TITLE=0 starts a session without a generated title.
  • /handoff <goal> opens an editable prompt.
  • subagent with a single agent, and a chain using {previous}.

Releasing

Publishing uses npm trusted publishing (OIDC). There is no long-lived npm token and no NPM_TOKEN secret.

A brand-new package cannot publish its first version through OIDC, because npm's trusted-publisher settings only exist after the package exists. Bootstrap once:

  1. npm login, then npm publish --access public from a clean checkout.
  2. On npmjs.com, open the package → Settings → Trusted publishing → GitHub Actions and set:
    • organization: sassywares
    • repository: sassy-pi-extensions
    • workflow filename: publish.yml
    • environment: blank
    • allowed actions: enable npm publish (do not leave it stage-only)
  3. Bump version in package.json, commit, then tag and push. The workflow publishes with OIDC and provenance.
git tag -a v0.3.1 -m v0.3.1
git push origin v0.3.1

The workflow skips publishing if the tag's version is already on npm. A new trusted publisher must complete its first OIDC publish within 2 days of configuration, or npm expires it.

Repository maintenance

  • Commit changes under extensions/ and agents/, and update README.md when behavior or configuration changes.
  • Tag releases (v0.3.0, v0.3.1, …) so installs can pin a ref. See Releasing.
  • Bump version in package.json to match the tag before pushing it.
  • AGENTS.md documents the workflow for agents working on this repo.
  • CONCEPTS.md holds the vocabulary.