pi-system-prompt-trim

Trim pi's own `docs` section out of every request: its doc paths, topic index and reading rules move into an on-demand `pi-docs` skill, and the always-on section is blank. Nothing else in the prompt is touched

Packages

Package details

extension

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

$ pi install npm:pi-system-prompt-trim
Package
pi-system-prompt-trim
Version
0.1.2
Published
Nov 4, 2026
Downloads
499/mo · 48/wk
Author
tangentyh
License
MIT
Types
extension
Size
39.6 KB
Dependencies
0 dependencies · 1 peer
Pi manifest JSON
{
  "extensions": [
    "./system-prompt-trim.ts"
  ]
}

Security note

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

README

pi-system-prompt-trim

Transcribes pi's own docs system-prompt section into a generated, on-demand pi-docs skill, so every request stops paying for a topic index that only matters on the rare turn you ask about pi itself.

before   <docs> 1 439 chars — routing sentence, doc paths, topic → file index, reading rules
after    <docs>    16 chars — blank; the whole index lives in the `pi-docs` skill

Nothing about pi's docs is hard-coded here. The skill is generated from the section the running install actually renders, so a pi release that adds a topic, rewrites the rules, or an install variant that appends a caveat — Pi-Bolt's pi-bolt update note, for instance — keeps its wording and stays reachable.

A pi update does not cold-start your conversation's prompt cache. The skill's path is keyed by install — pi-coding-agent for pi, pi-bolt for Pi-Bolt — and not by pi's version, so an upgrade rewrites the skill's body while the prompt and the location it advertises hold still, and the provider's cached prefix survives the upgrade. A version-keyed path would move on every release, invalidating that prefix for the rest of the conversation — a cost far larger than this extension saves. See The generated skill.

The other direction does cost money: resuming the same session under a different install changes the path in the recorded prompt, so the cache breaks anyway. That one is outside this extension's control, so it says so at startup instead of leaving you to notice the bill — see Resuming under another install.

Install

pi install ./extensions/system-prompt-trim        # local
pi install npm:pi-system-prompt-trim              # npm
pi -e ./extensions/system-prompt-trim             # this session only

Requires pi 1.3 or newer — earlier releases build the system prompt from a flat options object without the named section map (and skill list) this extension writes to.

What moves, what stays, what goes

The docs section is the only one this extension trims. Every other section — skills, guidelines, tool notes, project context — is left exactly as pi built it. Those carry standing instructions rather than lookup data, so moving one behind a skill would change behaviour on turns that never mention it, and a section-level trim is a decision each one has to earn on its own. The name describes the category the extension belongs to, not a promise to touch more of the prompt than docs.

pi's docs section is a routing sentence followed by bullets.

Text Where it goes
- bullets: the three doc roots, the topic → file index, the reading rules, a variant's caveats about the same material the pi-docs skill, verbatim
pi's routing sentence (Pi documentation (read only when…)) dropped — the skill's description routes on the same topics, and on more
Any other line that is not a bullet stays in the prompt, verbatim

Bullets are lookup data: they only matter once the model has decided to read pi's docs, which is exactly when a skill loads. A line without a bullet is the safe default — it is more likely a standing instruction than lookup data, and burying one in a skill that loads only on docs questions would change behaviour on unrelated turns. That is the one thing blanking does not touch: if pi or a variant adds an instruction inside <docs> without a bullet, it stays, and the section is not blank at all.

The routing sentence is dropped for the same reason it was never worth a pointer line. It gates reading on "the user asks about pi itself, its SDK, extensions, themes, skills, or TUI"; the generated skill's description gates on that list plus CLI, providers, models, MCP servers, codemode, settings, sessions and SDK, and adds "or when working on pi or on a pi extension". The description is the text skill matching actually consumes, and <skills> is rendered in every prompt this extension trims — the handler bails without a reader tool and again unless the skill is really advertised. So the routing was already stated where it does work, and the always-on copy was 110 characters per request spent repeating it. Its removal is by shape (Pi documentation (…):), not by position: a variant's reshaped or inserted line survives.

What is left is a single space, because the section cannot be deleted. pi merges sections with if (content) — a truthiness test with no trim — so "" and null are skipped and pi renders its whole section again; a space is the smallest value that still replaces it, and 15 of the 16 bytes left are the <docs> wrapper itself. An earlier version put an 83-character pointer line there; it was a second copy of the description, so it went.

The paths can move now, which they could not when the skill shipped as a static file: they are absolute and specific to the running install, so a file in the package cannot state them. A file written on the machine can.

Prompt cost of the change, measured on a brew install of pi 1.4.0 where the bullets name that install's absolute doc paths: 1 439 → 16 chars (Pi-Bolt's bundle adds its own caveat bullet and starts at 1 498 — the paths, and so the saving, scale with the install). The trimmed section does not grow when pi adds topics: the saved text is the section's bullets, not a copy of today's index.

The generated skill

<agent dir>/cache/pi-system-prompt-trim/<install id>/pi-docs/SKILL.md — on a default install, ~/.pi/agent/cache/pi-system-prompt-trim/pi-coding-agent/… — written only when its content changes:

  • Not the temp directory. Every skill's absolute filePath is rendered into its <skills> entry, so the advertised location is in the prompt and has to hold still between runs. $TMPDIR does not: it is per login session on macOS, fresh per container, and emptied by OS cleanup. A location that moves makes pi record a new sections.skills patch on the next resume, and a changed system prompt invalidates the provider's cached prefix for the entire conversation — far more than this extension saves. pi's own per-user state does not move.
  • One directory per install, named after the pi package. pi-coding-agent for pi, pi-bolt for Pi-Bolt. Two installs on one machine must not share one file: the body is install-specific instruction, and the model reads it later in the turn, so the last writer would hand a Pi-Bolt session pi's transcription — dropping the do not suggest pi update caveat — or the reverse. The id carries no version, and that is the cache benefit: only the path is prompt state, so brew's Cellar, an npx or pnpm store and a dev checkout all end in pi-coding-agent, and a pi-bolt-<platform>-<arch> bundle is pi-bolt — a pi update rewrites the body while the prompt, and so the provider's cached prefix, stays byte-identical. (Two versions of the same install do share one file, so for the few turns in which both run, the last writer's body wins — the paths differ, the topics barely do.)
  • Not ~/.pi/agent/skills. That directory is scanned and listed, so a generated skill there would show up in pi's own skill diagnostics and collide by name with a user's pi-docs; cache/ is neither scanned nor listed. It does outlive pi remove — see Off switch.
  • Registered in the same run that writes it. The skill is pushed onto the prompt's skill list from the same before_agent_start handler, so it is advertised before the prompt that mentions it is sent. No resources_discover startup ordering, no "the skill only exists from the next session" bootstrap, and a resumed session needs no disk state.
  • Static frontmatter. Only the body is install-specific; the name and description are constants, so the always-on skills section does not churn between machines. The body ends with the bullets exactly as pi rendered them.

Resuming under another install

A session persists the prompt it sent: the first request as one system message holding every section, later changes as system messages that patch sections by name (pi's docs/session-format.md). The <skills> section is part of that prompt, absolute pi-docs path included.

So resuming a session under the other install is the one case where this extension's own path change costs real money: the recorded prompt names …/pi-coding-agent/pi-docs/SKILL.md, this run advertises …/pi-bolt/…, pi records the difference as a section patch, and the provider's cached prefix is invalidated for the rest of the conversation.

session_start replays the recorded prompt, compares that path with this run's, and warns once when they differ:

This session was recorded by pi (pi-coding-agent) and is now running under
Pi-Bolt (pi-bolt): the pi-docs skill path changed, so the provider's cached
prompt prefix is invalidated for the rest of this conversation.
  • The branch is the signal, not reason. pi -c, pi --session <file> and pi --fork <file> all report reason: "startup" in pi 1.4.0 (probe extension, print mode); only a runtime switch says "resume". No recorded system message means no warning — which is why a fresh session is silent.
  • Only what it can substantiate. It names the two installs when the paths carry different ids, and the two paths when the same install moved (another agent dir, say). A prompt that changed for any other reason — a pi upgrade's own sections, a new project skill — still breaks the cache, with no warning from here.
  • Free, and fail-closed. It reads entries and calls ctx.ui.notify once: no provider request, no appended entry, no change to the trimmed section. An unreadable session, or a recorded pi-docs some other file provides, says nothing.

How it hooks in

before_agent_start gives handlers the prompt's name → text section map and its skill list (systemPromptOptions.sections / .skills). The handler splits the section pi actually built, writes the skill, advertises it, checks the skill is really on in the prompt it just rendered, and blanks sections.docs. pi persists the result as a normal section patch, so prompt caching and the transcript's structured prompt state are unaffected — given that the advertised location is the same on the next run, which is why the file lives in pi's own state directory rather than a temp one. (Returning systemPrompt instead would replace the whole prompt for the run — not what this extension wants.)

The source of truth is the rendered prompt, not a constant, so it fails closed, leaving pi's section exactly as built:

  • no section map (pi before 1.3), or no parseable docs section (a SYSTEM.md that replaces pi's prompt, or another extension's rewrite);
  • no read or bash tool selected — pi omits the skills section, so trimming would put the index out of reach;
  • no skill list in the prompt options to advertise into;
  • the skill is not on. After advertising, the handler re-reads the prompt and requires a <name>pi-docs</name> entry inside its skills section. An entry in the options is no proof: pi leaves a skill out when it sets disable-model-invocation: true, and a user's own switched-off pi-docs takes the name this extension would have advertised. Pointing at a skill the model cannot see would cost the index and the paths — worse than the section it replaced;
  • the write throws — a read-only or sandboxed agent dir must not cost the model its doc paths.

It is also idempotent: the same session re-derives the same blank section, and an unchanged skill file is not rewritten, so no repeated section deltas are recorded.

Off switch

Remove the package (pi remove ./extensions/system-prompt-trim) and pi's own docs section returns: the extension only ever replaces that section per run, and keeps no state of its own. The generated file is the one thing it leaves behind — it has to outlive the run, and the OS temp cleanup that a session resume would run into — so delete it by hand if you want it gone:

rm -rf ~/.pi/agent/cache/pi-system-prompt-trim

Alternatives

Two other extensions already move a docs block out of the prompt; neither transcribes pi's current wording into a skill file the package itself manages. docs/PRIOR-ART.md has the full comparison, dated to when this package was designed.

  • pi-extension-docs-skill also transcribes the block — into ~/.pi/agent/skills/pi-docs/SKILL.md, so the skill follows pi's wording at the cost of writing into your agent dir (it outlives pi remove), stripping only once the skill file already existed at session start, and replacing the whole prompt for the run.
  • @ssk_dev/pi-docs-slim removes the block entirely and puts it back for one run on /pi <question>. Cheaper per request, but the model cannot reach the docs on its own, only when you type the command.

Layout

system-prompt-trim.ts    the extension: split pi's section, write the skill, patch the prompt
tests/test.ts           checks against pi 1.3.0's section text and Pi-Bolt's appended line
docs/PRIOR-ART.md       comparison with the packages above, dated