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

@elvinw/pi-qq

v0.5.2

Published

/qq — quick side questions for pi that don't enter the conversation context (Claude Code's /btw, for pi)

Readme

pi-qq — /qq quick side question

Ask a one-off "by the way" question without letting the Q&A enter the ongoing context — the same idea as Claude Code's /btw.

True deletion: dismissed threads are really gone

Mainline pi's session is append-only: dismissing a /qq thread can at best move the leaf back, leaving the Q&A as a dead branch in the file (visible in /tree). This extension closes that gap. At load time it additively installs pruneBranches(keepLeafId?) on SessionManager.prototype — keeping only the root→leaf path, rebuilding pi's own index, and rewriting the session file. Never overriding an existing method, and only when the running pi version is in the verified allowlist (config.patchTargetPiVersions, currently 1.1.0 and 1.2.0 — the patch touches private-by-convention internals, so a version is added only after confirming SessionManager is byte-identical).

Dismiss and /nvm then drop the thread through a ladder — the first tier that works wins:

  1. prune (pin matches the running pi): the thread is physically removed from the session file — no dead branch, same session id. (Other orphan branches are tidied too.)
  2. rewind (any other pi): the baseline — the thread is orphaned in the tree (visible in /tree). There is deliberately no fork tier: a fork would create a duplicate session file in /resume on every dismiss. A one-time notice makes the degradation visible.

Transient failure paths (no answer, timeouts) still use a plain rewind: they discard one small failed question and must not churn session files.

Good to know: the prune tier rewrites your session files in place (the thread's nodes are removed from the JSONL). The patch itself is in-memory only and additive — it refuses to install on any pi other than the exact pinned one, and uninstalling the extension leaves pi completely untouched. Still, if you run valuable sessions, keep your usual ~/.pi backups.

Commands

| Command | Tool policy during the question | |---|---| | /qq <question> | prompt asks the model to use no tools | | /qqro <question> | prompt asks the model to use only read-only tools (read, grep, find, ls) | | /ro | Side thread only: toggle the follow-up policy between no-tools and read-only | | /sub | Side thread only: start a sub-thread from the current position. It stays part of the SAME side session (a context-invisible boundary marker shows it in /tree and on resume); /nvm and /merge always act on the whole session. (Named /sub because pi's built-in /fork — fork the session — wins the bare /fork exact match.) | | /merge | Side thread only: keep everything — initial /qq + every follow-up + every sub-thread — as conversation. The side session becomes mainline, the mode ends, and the next message continues right after the last answer. | | /nvm | Side thread only: never mind — exit the mode and rewind the whole side session (initial /qq + follow-ups + sub-threads) to its first question, as if it never happened |

The side thread is visible everywhere:

  • Input box: while the thread is open, the editor's top border becomes a "qq side thread — … /ro read-only · /sub sub-thread · /merge to main · /nvm back" title (live: the sub-thread depth updates on /sub) and the footer status shows the live tool policy and depth.
  • Command list: hidden == not dispatchable. Inside the thread /qq and /qqro disappear from the list and do not run either (plain text is the question now). /ro, /sub, /merge and /nvm are not registered commands at all — an input-level handler owns them while the thread is open, and outside it they pass through to the model as ordinary messages, exactly like any unknown slash text. A mistyped mode command (/nvm', /subx, …) is a typo, not a command: inside the thread it runs as a follow-up question (the box IS the side conversation), with a note telling you the exact spelling.

Neither command touches the active tool set: the side request is a byte-identical prefix extension of your last turn, so on llama.cpp/vLLM it costs zero extra prefill (the server's prefix cache only grows, and the cache is still intact for the next main turn). Tool policy is two-layer:

  1. the prompt asks the model to comply (no tools / read-only only), and
  2. a hard guardrail blocks any out-of-policy tool call before it executes — the model receives the block reason as a tool error and falls back to answering in text. A rogue write/bash can never run during a side question.

How it works

The Q&A takes over the main transcript like a normal turn and stays there until you decide its fate. The first side answer ends in a keypress choice:

  • f → open the side thread: the input box becomes your side conversation. Plain text is the next side question (answered with the whole thread in context, no /qq prefix needed). /ro toggles the follow-up policy; /sub starts a sub-thread (a boundary within the same session — it does not change what /nvm and /merge span); /merge keeps the whole session as conversation. Once in the thread there is no keypress prompt after a follow-up answer — it simply stays on the branch and you keep typing the next follow-up. The session ends when you run /nvm (drop it), /merge (keep it), or when a normal (non-/qq) message lands via another path (rpc driver, genuinely unknown slash text, …) — that message absorbs the thread: it can never be rewound away again. (A mistyped mode command is NOT such a message — see near-miss above.)
  • exit mid-thread → the thread survives in the session file. When pi next starts on that session, the extension detects that the conversation ends in side Q&A and re-opens the side thread: an answered one re- enters the mode (type to follow up, /nvm drops it); one that was still streaming only restores the thread so /nvm can still drop it. A merged thread (its merge left a context-invisible close marker) and an absorbed one are correctly NOT re-opened.
  • m → merge (first answer only): the side Q&A becomes part of the conversation and the next message continues right after the answer. (In the thread, /merge is the command-level equivalent — same effect, any time.)
  • any other key → dismiss (first answer only): the whole side thread (every question and answer in it) is rewound away and the conversation continues as if it never happened. Printable keys pass through, so you can start typing your next prompt immediately.

Mechanically, a pi session is an append-only tree of entries and the model context is always built from the root→leaf path. /qq exploits that:

  1. Remembers the current leaf (homeLeaf), appends a marker entry, and sends the question (with its tool-policy note) — the Q&A lands on a temporary side branch.
  2. Waits for the run to fully settle (agent_settled).
  3. First answer: puts up "f follow-up · m merges · any other key dismisses" (footer status + notification) and waits for your keypress. Follow-up answer (side thread open): no keypress at all — the answer stays and the input box is already yours.
  4. On dismiss//nvm, drops the thread at its root — the leaf before the thread's first question, so a whole follow-up thread vanishes at once — via the first available tier: prune (exact pi match) → leaf rewind (any other pi). On merge, it simply doesn't rewind.

After a dismiss the exchange is excluded from all future model requests and compaction. With the self-patch active it is also physically removed from the session file; on any other pi it remains as a dead branch, visible in /tree (you can re-attach it later by navigating to it).

Compaction safety

A side question must never compact the main conversation. If the session is near its token limit, the side turn itself can trip auto-compaction — and a compaction entry stranded on the main line would truncate the real history out of context (its summary would have been written from side-branch context). So during a side turn pi-qq:

  • cancels auto-compaction (session_before_compact → cancel),
  • waits for true idle (no run, no compaction) before rewinding — navigateTree refuses while the session is busy,
  • notifies when a rewind fails instead of failing silently (the Q&A stays visible so you can see it; re-run the command to dismiss again),
  • warns up front when the context is ≥ 90% of the window (the side turn may overflow; /compact first is the clean move).

Cost note: the side request still sends the full current context (the model needs it to answer "which of the two approaches…"). What /qq saves is the recurring cost — the exchange never rides along in every subsequent turn.

Install

pi install npm:@elvinw/pi-qq

Works on any pi: on pi 1.1.0 or 1.2.0, dismissed threads are physically pruned from the session file (see above); on other pi versions the extension automatically degrades to the plain dead-branch behavior.

or from a local clone:

pi --extension ./pi-qq

or place this directory in ~/.pi/agent/extensions/ (personal) or .pi/extensions/ (project), then /reload.

No npm install is needed to run it: the only runtime import (CustomEditor, for the mode's input-box title) is provided by pi itself when it loads the extension.

Development

npm install        # pulls the published pi-coding-agent 1.2.0 types + tsc
npm run typecheck
npm test           # 57 scenario tests (node:test, no extra deps)

The pi-coding-agent dev-dependency is exactly pinned (no ^) because the self-patch — and the tests around it — target a verified pi version (1.2.0, the newest in the allowlist); it also exists for local typechecking against the published API. node_modules/ is git-ignored.

Tests

test/ runs the extension against a mock pi environment (the extension imports pi's types only — no runtime dependency — so a mock ExtensionAPI plus an in-memory session tree exercise the real logic, no pi process needed). The scenario matrix covers:

  • lifecycle — send → settle → PENDING → dismiss/merge, key semantics (case, pass-through vs consume), status line, prompt notes
  • threads — follow-up chains, context inheritance, thread absorption by a normal message, orphaning via /tree
  • side-thread mode — plain-text follow-ups, no keypress gate after a follow-up answer (the next plain text is the next follow-up), /ro toggling (and non-reset across follow-ups), /nvm (with and without a thread, in-flight guard), auto-exit on /compact//tree//new effects, recursion guard, slash pass-through, in-flight guard, full e2e loop, near-miss (a mistyped mode command like /nvm' runs as a follow-up question, thread intact, and passes through as an ordinary message outside the thread)
  • sub-threads & merge — /sub appends a context-invisible boundary (depth shown live in the status and the editor title) and the session continues; /nvm drops the WHOLE session (initial /qq + sub-threads); /merge keeps the whole chain in order + close marker and ends the mode; both pass through as ordinary messages outside the thread; both are refused while a question is in flight; resume re-enters at the right depth and the walker treats fork boundaries as transparent (unit-tested, incl. merged/absorbed-after-sub and unanswered-after-sub)
  • mode surface — autocomplete hides /qq+/qqro inside the thread and hidden == not dispatched (/ro, /sub, /merge and /nvm are input-level, not commands, and pass through as ordinary messages outside the thread); the editor border carries the live mode title in mode only
  • failures — no answer, settle timeout, failed question mid-thread, stuck-busy rewind
  • queue — busy-on-call, re-settle loop, queue timeout, in-flight guard
  • invariants — zero leaked subscriptions on every path (including mode exit), compaction cancellation, tool guardrail (block/allow matrix), session swap, empty session, preflight warning
  • resume — pi exited mid-thread: answered thread re-enters the mode (follow-up continues, /nvm drops the whole session, incl. sub-threads), merged/absorbed threads are not re-opened, unanswered (mid-stream) restore only the thread for /nvm, plain sessions untouched
  • true deletion — installSessionPrune on the exact pinned pi version (idempotent, version-mismatch refusal) and a real SessionManager integration test (prune keeps root→target, re-pins the leaf, rewrites the file, reopens cleanly); the drop ladder on dismiss and /nvm (prune / rewind tiers — never fork)

Safety

  • Tool policy is two-layer while the tool set itself stays untouched (deliberate, for cache preservation): the prompt asks the model to comply, and a tool_call guardrail blocks any out-of-policy call before it executes — the model sees the block reason as a tool error and answers in text instead. Nothing can write files or run commands during /qq.
  • If an answer is aborted or errors before producing text, only that question is rewound away immediately (nothing to read); the rest of an in-progress thread survives.
  • Exitting pi mid-thread never loses the thread: it is re-detected from the session file on the next start (see exit mid-thread above). Merge leaves a context-invisible close marker so a resumed session can tell a merged thread from an open one.
  • /new, /fork, or quit mid-question: the wait bails out; the side branch is just an orphan branch (harmless). Inside an open side thread these commands (and /compact, /tree navigation) end the mode automatically — the thread is absorbed or orphaned and plain text goes back to the main conversation.
  • In side-thread mode, plain text submitted while a question is still streaming is dropped with a warning (strictly serial — one question at a time, single-slot llama.cpp safe).
  • Double /qq//qqro is rejected while one is running or queued.
  • If the agent is running, the question is queued and runs automatically when the flow settles (aborting the flow unblocks it). Still strictly serial — compatible with single-slot llama.cpp (-np 1). A 2h wait cap drops the question rather than wedging the command.