Before submitting
Problem or opportunity
GENTLE_PI_REVIEW_RELAY_EXTENSIONS (shipped for #1158) is the supported way to re-admit provider/auth extensions (e.g. pi-claude-bridge) into the reviewer child via explicit -e flags. But its only transport is an environment variable, and environment variables are process-global by nature:
- Exported from shell startup (
~/.zshenv), it leaks into every other tool's environment even though it only has meaning for gentle-pi's reviewer relay. Env vars are process-global by nature, so there is no way to scope the allowlist to Pi without user-built machinery.
- Scoped alternatives are all user-built: a shell alias (misses non-interactive launchers) or a custom global Pi extension that mutates
process.env at load. The extension approach works — we validated the full lifecycle end-to-end with it — but every bridge user must write it themselves, and Pi's /reload does not pick up newly created extensions, so it fails silently until a full Pi restart.
Anyone routing review lenses to claude-bridge/* (or any extension-provided provider) needs this today, and there is no in-product way to configure it.
Proposed outcome
resolveReviewHostRelayExtensionPaths() (lib/review-host-relay.ts) additionally reads a gentle-pi-owned config source — for example ${gentlePiConfigHome}/review-relay.json with {"reviewerExtensionPaths": ["..."]} — with the environment variable, when set and non-empty, replacing the file entirely as a per-invocation override (same semantics as GENTLE_PI_AUTONOMOUS_MODE in runtime-guardrails). Validation stays exactly as today: absolute, existing paths, typed REVIEWER_CONFIG_INVALID refusal before anything launches.
A config file is user-owned and Pi-scoped by construction, so the allowlist can no longer leak into other runtimes' environments.
Happy to send the PR if this direction is approved.
Alternatives considered
~/.zshenv export: works, but leaks a Pi-only setting into every other process's environment.
- Shell alias/wrapper around
pi: covers interactive shells only; launchers and non-interactive invocations miss it.
- Custom global extension setting
process.env at extension load (~30 lines): our current working workaround, but per-user boilerplate, and invisible to /reload when newly created.
Additional context
Full native RDD lifecycle validated end-to-end through pi_host_relay with the bridge re-admitted via -e from the env allowlist: lens executed on a claude-bridge/* model, result admitted, review approved, authority burned.
Related: #1158 (origin of the env allowlist), #757 (silent model substitution when the provider extension is missing from the reviewer child — a first-class config source also narrows the window in which users run without any allowlist configured).
Before submitting
Problem or opportunity
GENTLE_PI_REVIEW_RELAY_EXTENSIONS(shipped for #1158) is the supported way to re-admit provider/auth extensions (e.g.pi-claude-bridge) into the reviewer child via explicit-eflags. But its only transport is an environment variable, and environment variables are process-global by nature:~/.zshenv), it leaks into every other tool's environment even though it only has meaning for gentle-pi's reviewer relay. Env vars are process-global by nature, so there is no way to scope the allowlist to Pi without user-built machinery.process.envat load. The extension approach works — we validated the full lifecycle end-to-end with it — but every bridge user must write it themselves, and Pi's/reloaddoes not pick up newly created extensions, so it fails silently until a full Pi restart.Anyone routing review lenses to
claude-bridge/*(or any extension-provided provider) needs this today, and there is no in-product way to configure it.Proposed outcome
resolveReviewHostRelayExtensionPaths()(lib/review-host-relay.ts) additionally reads a gentle-pi-owned config source — for example${gentlePiConfigHome}/review-relay.jsonwith{"reviewerExtensionPaths": ["..."]}— with the environment variable, when set and non-empty, replacing the file entirely as a per-invocation override (same semantics asGENTLE_PI_AUTONOMOUS_MODEin runtime-guardrails). Validation stays exactly as today: absolute, existing paths, typedREVIEWER_CONFIG_INVALIDrefusal before anything launches.A config file is user-owned and Pi-scoped by construction, so the allowlist can no longer leak into other runtimes' environments.
Happy to send the PR if this direction is approved.
Alternatives considered
~/.zshenvexport: works, but leaks a Pi-only setting into every other process's environment.pi: covers interactive shells only; launchers and non-interactive invocations miss it.process.envat extension load (~30 lines): our current working workaround, but per-user boilerplate, and invisible to/reloadwhen newly created.Additional context
Full native RDD lifecycle validated end-to-end through
pi_host_relaywith the bridge re-admitted via-efrom the env allowlist: lens executed on aclaude-bridge/*model, result admitted, review approved, authority burned.Related: #1158 (origin of the env allowlist), #757 (silent model substitution when the provider extension is missing from the reviewer child — a first-class config source also narrows the window in which users run without any allowlist configured).