@2wchuang/pro-advisor
Pi extension. A second opinion from a stronger reviewer model, kept in one persistent session per executor session.
Package details
Install @2wchuang/pro-advisor from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@2wchuang/pro-advisor- Package
@2wchuang/pro-advisor- Version
0.3.0- Published
- Sep 10, 2026
- Downloads
- 949/mo · 949/wk
- Author
- 2wchuang
- License
- MIT
- Types
- extension
- Size
- 123.6 KB
- Dependencies
- 2 dependencies · 3 peers
Pi manifest JSON
{
"extensions": [
"./index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
@2wchuang/pro-advisor
Pi extension. A second opinion from a stronger reviewer model — kept in one persistent session per executor session.
Forked from @juicesharp/rpiv-advisor
(MIT). The tool surface, /advisor command, config file, and picker are
unchanged; the advisor session layer is replaced. See
What changed from upstream.
Install
From npm:
pi install npm:@2wchuang/pro-advisor
Or from git — no npm account or registry involved:
pi install git:github.com/2wchuang/pro-advisor@v0.3.0
Restart your Pi session. Run /advisor to pick the reviewer model — nothing
happens until you do.
If you were running upstream
@juicesharp/rpiv-advisor, replace that entry in~/.pi/agent/settings.jsonrather than adding this one: both register a tool namedadvisor, and they share the same config file and session directory. See docs/RELEASING.md for the publisher-side setup.
What this does and does not claim
The upstream advisor is a stateless side-call: every advisor() call takes no
parameters, re-serialises the executor's whole conversation branch, and sends it
as a fresh single request. The reviewer sees continuous context because the
executor's history is replayed each time, but the advisor itself remembers nothing
between calls.
This fork makes two changes:
- the advisor is a real, persistent Pi
AgentSession, one per executor session, so a follow-up is a genuine continuation rather than a cold restart; - the advisor receives a brief the executor writes, not the conversation.
Why the brief replaced the transcript
The first iteration of this fork did forward the transcript, incrementally. It was measured, and removed — see docs/ISSUES.md I-9. A real 667,925-character delivery broke down as:
| Content | Share |
|---|---|
| executor thinking | 36.2% |
| tool inventory (the advisor calls no tools) | 21.5% |
| raw tool output | 21.1% |
| tool-call signatures | 17.2% |
| executor prose | 3.5% |
| the user's own words | 0.5% |
And it produced a fabrication failure: the payload rendered the transcript with
[Assistant tool calls]: / [Tool result (x)]: markers and ended on the
executor's own in-flight advisor() call, so the document's next natural line
was a tool result. The advisor continued the document instead of answering it. In
one reply 11,308 of 15,593 characters (72.5%) were invented executor activity —
including a commit hash that does not exist in the repository. That text re-entered
the executor's context looking exactly like the real transcript.
What is claimed: session continuity, and that the advisor sees only what the executor chose to send it.
What the executor must now do: author the brief. The advisor has no tools, no
conversation access, and no ability to inspect anything. It can only judge what it
is told — so cite primary sources (file:line, measured numbers) in evidence,
or the advisor can only take the reasoning on trust.
What is NOT claimed:
- Not a token saving relative to the upstream stateless design. Continuity is the goal. The advisor also keeps its own history, which is re-sent to its provider each turn like any other chat session — that prefix is the provider's to cache or bill, and this package does not promise either.
- Not faster by construction. Speed is a side effect, not a contract.
- No independent verification. The advisor cannot check a claim you did not state. It challenges your reasoning, not your facts.
Session identity
The advisor session is keyed by the executor session id, so:
| Executor action | Advisor behaviour |
|---|---|
Repeated advisor() calls |
same advisor session; each call carries its own brief |
/new |
new advisor session |
/fork |
new advisor session (no cross-branch contamination) |
/resume |
reopens the same advisor session — same id, same history |
/advisor → different model |
setModel() on the same session; identity survives the switch |
/advisor → No advisor |
sessions disposed; a later re-enable starts fresh |
Known risk: stale bias in a long-lived advisor session
The advisor's session accumulates its own prior conclusions. If an early consultation reasoned from a premise that later turned out to be wrong, that reasoning stays in its history and can keep colouring later advice. The stateless upstream design read the current branch every call and so carried no such residue.
Nothing in this package demonstrates that the advisor withdraws a stale
conclusion. Treat stale bias as an open risk, and prefer /new when a line of
reasoning has gone definitively wrong. (The pre-I-9 design attempted a "rebase"
that re-stated the transcript and told the advisor its earlier reading was
superseded; that mechanism is gone with the mirror, so this risk is now
unmitigated by wording as well.)
Fixed: compaction inverted the advisor's identity
Observed live, on the first session long enough to cross Pi's auto-compaction
threshold (tokensBefore: 510,091): the advisor stopped advising and asked the
executor for instructions — "I need your guidance on where we stand" — then
listed the executor's publishing milestones as its own achievements.
Cause: an advisor session is a real Pi AgentSession, so Pi's auto-compaction
applied to it too. Its summarizer is written for the executor — the template
asks for ## Goal, ## Constraints & Preferences, ## Progress, ## Next Steps.
The advisor's transcript is a mirror of the executor's work, so summarising it
produced a document describing the executor's task as the advisor's own, and the
advisor adopted that identity.
Upstream could not hit this: a stateless side-call keeps no session, so there was nothing to compact. It is a hazard the persistent design introduced.
Fixed by disabling auto-compaction on the advisor session
(session-pool.ts) — belt and braces now that the payload is a brief: a summary
of a brief cannot describe the executor's task as the advisor's own, but the
inversion is too costly to leave to that argument alone.
Sessions are stored under ~/.pi/agent/pro-advisor/.
Safety
The advisor session is constructed with extensions, skills, prompt templates, themes, context files, and all tools disabled. It cannot call a tool, cannot write to your transcript, and cannot recursively load this extension.
Failure handling is conservative: a failed, aborted, or empty consultation never claims success. An empty response is retried exactly once, with a short corrective prompt in the same advisor session. Aborted and provider-error replies are never retried.
A call with no question is refused before a session is created or a paid
call is made.
Payload shape is load-bearing
The consultation payload is built by advisor/brief.ts and is deliberately not
a continuable transcript. That is a correctness property, not a style preference —
see docs/ISSUES.md I-9. Two rules are enforced by tests:
- the payload never emits
[Assistant]:/[Assistant thinking]:/[Assistant tool calls]:/[Tool result (x)]:markers; - it always ends on an instruction, never on a pending action.
Fields are capped at 6,000 characters each and truncation is marked inline, so a clipped thought is not silently read as complete.
Configuration
Unchanged from upstream: ~/.config/rpiv-advisor/advisor.json (shared on
purpose, so an existing selection carries over).
{
"modelKey": "anthropic/claude-opus-4-5",
"effort": "high",
"disabledForModels": [
"anthropic/claude-opus-4-5",
{ "model": "openai/gpt-5.2", "minEffort": "high" }
]
}
| Key | What it does | Default |
|---|---|---|
modelKey |
Reviewer model as "provider/modelId". Written by /advisor. |
absent — advisor off |
effort |
Reviewer reasoning effort. Written by /advisor. |
absent — model default |
disabledForModels |
Executor models the advisor is stripped for. Plain strings block at any effort; { model, minEffort } blocks at or above that effort. |
[] |
guidance |
Overrides for the tool's promptSnippet / promptGuidelines. |
built-in |
The tool is stripped from the active set — so none of its prompt text enters the
system prompt — when no model is selected, the configured model is unavailable,
or the executor matches disabledForModels.
What changed from upstream
Most files are retained verbatim. The session layer is new:
| File | Status |
|---|---|
advisor/session-pool.ts |
new — persistent advisor session + pool |
advisor/brief.ts |
new — structured-payload construction (replaced the transcript mirror) |
advisor/status.ts |
new — /advisor-status: sessions, turns, on-disk history size |
advisor/execute.ts |
rewritten — drives the session with a brief instead of a stateless completion |
advisor/register.ts |
changed — structured schema; DEFAULT_PROMPT_GUIDELINES rewritten; see Advisor voice below |
index.ts, advisor/handlers.ts, advisor/restore.ts, advisor/command.ts |
minimally wired — pool injection, dispose on session switch/shutdown |
advisor/context.ts, advisor/pi-compat.ts |
removed — both existed only to shape a per-call payload and resolve a global completion for it |
advisor/mirror.ts |
removed — forwarded the executor transcript; measured 99.5% process noise and induced payload fabrication (I-9) |
everything else incl. advisor/config.ts, messages.ts, policy.ts, state.ts, inventory.ts, advisor-ui.ts, fuzzy.ts |
unchanged |
Advisor voice
Upstream's injected guidelines made the advisor a gate every non-trivial task had
to pass — "Call advisor BEFORE substantive work", "at least once before
committing to an approach and once before declaring done", "Give the advisor's
advice serious weight", "put the advisor's key guidance into your next visible
reply to the user". Observed consequences: mandatory escalation, the executor
reporting to the advisor rather than to the user, and the advisor's position
being restated as though the user had said it.
The rewritten defaults invert each of those: the user is named the
decision-maker ("if the advisor and the user disagree, the user wins"), there is
explicitly no minimum number of calls, and the advisor's views must be
attributed to the advisor and never to the user. Reporting a consultation is
limited to cases where it actually changed the plan, and framed as the executor's
own decision. The original strings are retained as
UPSTREAM_PROMPT_GUIDELINES for reference and regression-testing.
See docs/ISSUES.md for each finding with its evidence, and repo-guards.test.ts
for the guards that keep these regressions from returning.
Test coverage
236 tests. Upstream's are retained where they still describe the code, and transport-specific tests were replaced rather than dropped:
advisor/pi-compat.test.tsandadvisor.strip.test.tstested the removed completion resolution and tail-massaging; they are replaced byadvisor.brief.test.ts(payload construction + I-9 shape guards) andadvisor.session-pool.test.ts(session identity, isolation, resume, concurrency, zero tools).advisor.mirror.test.tscovered incremental delivery and rebase planning for the mirror; it was deleted with the mirror. The equivalent concern — what the advisor actually receives — now lives inadvisor.brief.test.ts.advisor.execute.test.tswas rewritten against an injectableAdvisorSessionDriverseam. The envelope contract is preserved — success, auth failure, abort, provider error, thrown error, bounded empty-response retry — while thecompleteSimpletransport assertions are gone with the transport.
Commands
| Command | Purpose |
|---|---|
/advisor |
Pick the reviewer model and reasoning effort |
/advisor-status |
Show advisor sessions, accumulated turns, and on-disk history size |
/advisor-status exists because a persistent advisor session grows its history on
every consultation and nothing previously surfaced how large it had become. It
reports file bytes as a proxy for history size — not tokens, not cost, so the
"no guaranteed token saving" disclaimer above stays checkable rather than a
matter of faith.
Development
npm install
npm run check # typecheck + tests
npm run pack:check # verify the published tarball contains every runtime module
License
MIT. Derivative of @juicesharp/rpiv-advisor (MIT, Copyright (c) 2026
juicesharp); see LICENSE for the retained original notice.