Skip to content

fix(pi): honest capability warning when the host lacks ctx.isProjectTrusted - #1355

Merged
backnotprop merged 1 commit into
mainfrom
fix/1353-trust-warning-message
Aug 21, 2026
Merged

backnotprop merged 1 commit into
mainfrom
fix/1353-trust-warning-message

Conversation

@backnotprop

Copy link
Copy Markdown
Owner

TLDR: The Pi extension's capability-absent trust warning told every host to "update Pi". That is correct advice on a real Pi older than 0.79.1, but wrong and confusing on forks like oh-my-pi (17.4.0) that never implemented ctx.isProjectTrusted(). The two cases are not reliably distinguishable at runtime, so the warning now states the capability gap honestly for both audiences, without guessing the host. Fail-closed behavior is byte-for-byte unchanged; only the warning text changed.

New message:

This host does not expose project trust (ctx.isProjectTrusted, Pi 0.79.1+). Project-local config (.pi/plannotator.json) is disabled; bundled and global config still load.

Closes #1353. Thanks to @materemias for the report.

The two audiences

  1. Real Pi older than 0.79.1. ctx.isProjectTrusted() shipped in Pi commit db3f9953e ("feat(coding-agent): expose project trust to extensions", closes pi#5523), whose earliest release tag is v0.79.1, confirmed by Pi's CHANGELOG entry under [0.79.1] - 2026-06-09. For this audience "update Pi" was correct.
  2. oh-my-pi 17.4.0. The current OMP tree has zero occurrences of isProjectTrusted; its ExtensionContext (packages/coding-agent/src/extensibility/extensions/types.ts:454-524, built in runner.ts:1146-1194) simply never adopted the capability. "Update Pi" is wrong advice here: no update fixes it, and the user is not even running Pi.

Why one message instead of host detection

Neither host gives an extension a reliable identity from the context:

  • Pi's ExtensionContext (packages/coding-agent/src/core/extensions/types.ts:307-348) has no version or app-name field. The branding constants Pi itself uses for fork detection (APP_NAME, PACKAGE_NAME in src/config.ts:488-491) are not exported to extensions.
  • OMP's ExtensionContext likewise exposes no host name or version. Identity exists only via the pi API object (pi.pi.VERSION) or shape sniffing (pi.zod, ctx.invokeTool), all heuristic and version-fragile, and a fork resolving the host package resolves to its own values anyway.

Since detection cannot be proven reliable, the message is one sentence pair that is true for both audiences: it names the missing capability and the Pi version that introduced it (so a real-Pi user knows to update), and says what still works. The "bundled and global config still load" claim is verified in code: loadPlannotatorConfig (apps/pi-extension/config.ts:240-271) always loads the internal and global configs and gates only project-local .pi/plannotator.json on projectTrusted.

Behavior and capability contract: unchanged

  • Capability absent: still fails closed (project-local config skipped), now with the honest warning.
  • Capability returns true: project-local config loads. This is both the trusted real-Pi path and the OMP path once fix(extensions): expose ctx.isProjectTrusted for legacy pi extensions can1357/oh-my-pi#7958 ships its isProjectTrusted: () => true shim; that shim adds a plain function on both of OMP's context builders, and our typeof probe works through OMP's prototype-delegated handler contexts, so the existing guard works there with no change on our side.
  • Capability returns false: still fails closed, no warning (the host answered; that is not a capability gap).
  • Capability throws (real Pi throws on a stale context via runner.assertActive): still propagates, config loading never runs, project-local config still cannot load. Now pinned by a test so a future try/catch cannot silently flip it to trusted.

Nothing else in the extension breaks under OMP's context shape: the only members we touch (ui, hasUI, cwd, sessionManager, modelRegistry, model, isIdle, isProjectTrusted) all exist on OMP's context except the feature-detected isProjectTrusted.

Tests

  • Updated the capability-absent test to pin the new message deliberately (marked as a copy pin: this string is user-facing advice that OMP 17.4.0 triggers the Pi trust warning in Plannotator 0.27.4 #1353 proved can mislead).
  • New test: host reports trust, project-local config loads (the OMP-after-7958 and trusted-Pi path), no warning.
  • Extended: explicit false fails closed with no capability warning.
  • New test: throwing isProjectTrusted propagates and project config stays unloaded.

bun test apps/pi-extension: 224 pass; the only 6 failures are the pre-existing environmental "pi review server" GitButler/semantic-diff/workspace failures, identical before and after this change. bun run typecheck green.

Smoke: real Pi 0.84.1 (installed binary) loaded the modified extension from source in both trusted (--approve) and untrusted (--no-approve) print-mode runs; both reached the model call with no capability warning and no errors (a control run without -e rejects the extension-registered --plan flag, proving the extension loaded). The warning path itself requires an old Pi or an OMP host, neither of which is runnable in this environment (installed Pi is 0.84.1; OMP has no binary and its checkout is read-only), so that path is covered by the unit tests with context doubles derived from the two checkouts' actual shapes.

AI-assisted (Claude) under maintainer direction.

The capability-absent warning told every host to update Pi, but forks
that never implemented ctx.isProjectTrusted (oh-my-pi) also hit this
path, and update Pi is wrong advice there. Neither Pi's nor oh-my-pi's
extension context exposes a host name or version, so the two audiences
cannot be reliably told apart at runtime. The warning now states the
capability gap without guessing the host, and says what still works:
bundled and global config load regardless (only project-local config is
trust-gated in loadPlannotatorConfig).

Fail-closed behavior is unchanged: capability absent still skips
.pi/plannotator.json, a host-provided true is still honored verbatim
(the oh-my-pi shim in can1357/oh-my-pi#7958 will work unmodified), and
a throwing trustFn still propagates. Tests pin all four paths.

Reported by @materemias in #1353.
@backnotprop
backnotprop merged commit 752d331 into main Aug 21, 2026
28 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OMP 17.4.0 triggers the Pi trust warning in Plannotator 0.27.4

1 participant