feat(pi): support the pi extension ecosystem with zero injection by default - #189

Merged
Tryanks merged 7 commits into
mainfrom
feat/pi-extension-support
Jul 30, 2026
Merged

feat(pi): support the pi extension ecosystem with zero injection by default#189
Tryanks merged 7 commits into
mainfrom
feat/pi-extension-support

Conversation

@Tryanks

Copy link
Copy Markdown
Owner

Summary

Makes user-installed pi extensions first-class inside tcode's pi sessions, while defaulting to zero tcode injection in keeping with pi's minimalism — instrumentation is something the user opts into, not something tcode imposes.

Default experience (respects pi's philosophy)

  • A pi session is now a bare pi --mode rpc: no injected extension, no injection env vars, no preview MCP token minting, no startup toast.
  • Extension-registered tools run natively; extension select/input/editor dialogs surface through the native user-input panel (with editor prefill via a new optional UserInputQuestion.prefill); displayed pi.sendMessage messages appear as Work Log items; extension notify warnings/errors surface as session warnings.

Opt-in toggles on the pi provider card (both off by default)

  • Native approvals — injects the tcode permission gate for supervised / auto-accept-edits modes only. The gate resolves tool provenance via pi.getAllTools(): builtins keep the existing policy; extension tools go through native approval (approval card names the extension path); an extension shadowing a builtin name (read, bash, …) always requires approval and renders as ToolUse, never as a plain shell command; unresolvable provenance stays blocked fail-closed. Without the toggle, stored supervised modes are coerced to full access in SessionOptions only (the persisted preference survives), and the mode picker shows the supervised entries disabled with a pointer to the setting.
  • Trust project extensions — launches pi with --approve so project-local .pi extensions/settings/skills load (pi's RPC mode never shows its interactive trust prompt).

Warning policy

The "MCP tools unavailable" toast now fires only when orchestrate or computer-use were explicitly enabled but can't attach (pi has no MCP client); preview no longer triggers it.

Test plan

  • cargo fmt --check, cargo clippy --workspace --all-targets -- -D warnings, cargo test --workspace all green (new tests: gate mode matrix, approval mapping incl. shadowed builtins, dialog request/response/cleanup, custom-message display rules, session-options coercion + preview drop, settings round-trips, launch-args ordering, locale parity).
  • Live pi e2e: extension tool confirmed + executed after approval; shadowed read gated instead of auto-allowed; denial honored.

🤖 Generated with Claude Code

Tryanksand others added 7 commits July 30, 2026 15:06
…ing notifications
pi has no MCP client, so the session warning now names which tcode tool
families (preview browser, orchestration, computer-use) are unavailable
instead of a blanket message. Extension ctx.ui.notify calls at warning/
error level now surface as session warnings instead of being dropped,
both in steady state and during the startup handshake.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…via native approval
The gate now resolves tool provenance with pi.getAllTools(): builtins keep
the existing policy, extension/SDK tools are blocked in read_only, allowed
in full_access, and confirmed through tcode's native approval elsewhere.
A tool whose builtin name was shadowed by an extension is treated as an
extension tool, and its approval card maps to ToolUse (never ExecCommand/
FileChange) with the extension path and shadowing noted in the detail.
Tools with unresolvable provenance stay blocked, fail closed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…prove
pi in RPC mode never shows its project-trust prompt, so project-local .pi
extensions/settings/skills were silently ignored. Each pi profile now has
an off-by-default toggle that appends --approve to the launch args after
the profile's configured launch arguments.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Extension select/input/editor dialogs now map onto the native user-input
panel instead of being auto-cancelled: select options become choices,
input placeholders fold into the question, and editor prefill seeds the
free-text field (new optional UserInputQuestion.prefill, additive for
all providers). Pending dialogs are resolved with pi's cancelled
response on turn end, interrupt, cancel, and shutdown, and dialogs
arriving during the startup handshake are auto-cancelled.
Displayed custom messages from pi.sendMessage now appear as Work Log
items keyed by their customType instead of being dropped.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
pi sessions now launch as a bare 'pi --mode rpc' by default: no permission
extension, no TCODE_PI_APPROVAL_MODE env, and no preview MCP registration
(pi has no MCP client to attach it). A new off-by-default per-profile
'Native approvals' toggle opts back into the tcode permission gate, which
is injected only for the modes that need it (supervised and auto-accept
edits); read-only stays on pi's native --tools filter either way.
Without the toggle, stored supervised modes are coerced to full access in
SessionOptions only — the persisted preference survives and resurfaces
when the toggle is enabled — and the approval-mode picker shows the two
supervised entries disabled with a pointer to the provider setting. The
unattached-MCP warning now fires only for explicitly enabled orchestrate
or computer-use registrations, so default pi sessions start silently.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Tryanks
Tryanks enabled auto-merge July 30, 2026 08:06
@Tryanks
Tryanks merged commit 3625823 into mainJul 30, 2026
3 checks passed
@Tryanks
Tryanks deleted the feat/pi-extension-support branch July 30, 2026 08:12
Sign up for freeto 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.

1 participant

@Tryanks
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

feat(pi): support the pi extension ecosystem with zero injection by default - #189

Merged
Tryanks merged 7 commits into
mainfrom
feat/pi-extension-support
Jul 30, 2026
Merged

feat(pi): support the pi extension ecosystem with zero injection by default#189
Tryanks merged 7 commits into
mainfrom
feat/pi-extension-support

Conversation

@Tryanks

Copy link
Copy Markdown
Owner

Summary

Makes user-installed pi extensions first-class inside tcode's pi sessions, while defaulting to zero tcode injection in keeping with pi's minimalism — instrumentation is something the user opts into, not something tcode imposes.

Default experience (respects pi's philosophy)

  • A pi session is now a bare pi --mode rpc: no injected extension, no injection env vars, no preview MCP token minting, no startup toast.
  • Extension-registered tools run natively; extension select/input/editor dialogs surface through the native user-input panel (with editor prefill via a new optional UserInputQuestion.prefill); displayed pi.sendMessage messages appear as Work Log items; extension notify warnings/errors surface as session warnings.

Opt-in toggles on the pi provider card (both off by default)

  • Native approvals — injects the tcode permission gate for supervised / auto-accept-edits modes only. The gate resolves tool provenance via pi.getAllTools(): builtins keep the existing policy; extension tools go through native approval (approval card names the extension path); an extension shadowing a builtin name (read, bash, …) always requires approval and renders as ToolUse, never as a plain shell command; unresolvable provenance stays blocked fail-closed. Without the toggle, stored supervised modes are coerced to full access in SessionOptions only (the persisted preference survives), and the mode picker shows the supervised entries disabled with a pointer to the setting.
  • Trust project extensions — launches pi with --approve so project-local .pi extensions/settings/skills load (pi's RPC mode never shows its interactive trust prompt).

Warning policy

The "MCP tools unavailable" toast now fires only when orchestrate or computer-use were explicitly enabled but can't attach (pi has no MCP client); preview no longer triggers it.

Test plan

  • cargo fmt --check, cargo clippy --workspace --all-targets -- -D warnings, cargo test --workspace all green (new tests: gate mode matrix, approval mapping incl. shadowed builtins, dialog request/response/cleanup, custom-message display rules, session-options coercion + preview drop, settings round-trips, launch-args ordering, locale parity).
  • Live pi e2e: extension tool confirmed + executed after approval; shadowed read gated instead of auto-allowed; denial honored.

🤖 Generated with Claude Code

Tryanksand others added 7 commits July 30, 2026 15:06
…ing notifications
pi has no MCP client, so the session warning now names which tcode tool
families (preview browser, orchestration, computer-use) are unavailable
instead of a blanket message. Extension ctx.ui.notify calls at warning/
error level now surface as session warnings instead of being dropped,
both in steady state and during the startup handshake.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…via native approval
The gate now resolves tool provenance with pi.getAllTools(): builtins keep
the existing policy, extension/SDK tools are blocked in read_only, allowed
in full_access, and confirmed through tcode's native approval elsewhere.
A tool whose builtin name was shadowed by an extension is treated as an
extension tool, and its approval card maps to ToolUse (never ExecCommand/
FileChange) with the extension path and shadowing noted in the detail.
Tools with unresolvable provenance stay blocked, fail closed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…prove
pi in RPC mode never shows its project-trust prompt, so project-local .pi
extensions/settings/skills were silently ignored. Each pi profile now has
an off-by-default toggle that appends --approve to the launch args after
the profile's configured launch arguments.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Extension select/input/editor dialogs now map onto the native user-input
panel instead of being auto-cancelled: select options become choices,
input placeholders fold into the question, and editor prefill seeds the
free-text field (new optional UserInputQuestion.prefill, additive for
all providers). Pending dialogs are resolved with pi's cancelled
response on turn end, interrupt, cancel, and shutdown, and dialogs
arriving during the startup handshake are auto-cancelled.
Displayed custom messages from pi.sendMessage now appear as Work Log
items keyed by their customType instead of being dropped.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
pi sessions now launch as a bare 'pi --mode rpc' by default: no permission
extension, no TCODE_PI_APPROVAL_MODE env, and no preview MCP registration
(pi has no MCP client to attach it). A new off-by-default per-profile
'Native approvals' toggle opts back into the tcode permission gate, which
is injected only for the modes that need it (supervised and auto-accept
edits); read-only stays on pi's native --tools filter either way.
Without the toggle, stored supervised modes are coerced to full access in
SessionOptions only — the persisted preference survives and resurfaces
when the toggle is enabled — and the approval-mode picker shows the two
supervised entries disabled with a pointer to the provider setting. The
unattached-MCP warning now fires only for explicitly enabled orchestrate
or computer-use registrations, so default pi sessions start silently.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Tryanks
Tryanks enabled auto-merge July 30, 2026 08:06
@Tryanks
Tryanks merged commit 3625823 into mainJul 30, 2026
3 checks passed
@Tryanks
Tryanks deleted the feat/pi-extension-support branch July 30, 2026 08:12
Sign up for freeto 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.

1 participant

@Tryanks
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(pi): support the pi extension ecosystem with zero injection by default - #189

Merged
Tryanks merged 7 commits into
mainfrom
feat/pi-extension-support
Jul 30, 2026
Merged

feat(pi): support the pi extension ecosystem with zero injection by default#189
Tryanks merged 7 commits into
mainfrom
feat/pi-extension-support

Conversation

@Tryanks

Copy link
Copy Markdown
Owner

Summary

Makes user-installed pi extensions first-class inside tcode's pi sessions, while defaulting to zero tcode injection in keeping with pi's minimalism — instrumentation is something the user opts into, not something tcode imposes.

Default experience (respects pi's philosophy)

  • A pi session is now a bare pi --mode rpc: no injected extension, no injection env vars, no preview MCP token minting, no startup toast.
  • Extension-registered tools run natively; extension select/input/editor dialogs surface through the native user-input panel (with editor prefill via a new optional UserInputQuestion.prefill); displayed pi.sendMessage messages appear as Work Log items; extension notify warnings/errors surface as session warnings.

Opt-in toggles on the pi provider card (both off by default)

  • Native approvals — injects the tcode permission gate for supervised / auto-accept-edits modes only. The gate resolves tool provenance via pi.getAllTools(): builtins keep the existing policy; extension tools go through native approval (approval card names the extension path); an extension shadowing a builtin name (read, bash, …) always requires approval and renders as ToolUse, never as a plain shell command; unresolvable provenance stays blocked fail-closed. Without the toggle, stored supervised modes are coerced to full access in SessionOptions only (the persisted preference survives), and the mode picker shows the supervised entries disabled with a pointer to the setting.
  • Trust project extensions — launches pi with --approve so project-local .pi extensions/settings/skills load (pi's RPC mode never shows its interactive trust prompt).

Warning policy

The "MCP tools unavailable" toast now fires only when orchestrate or computer-use were explicitly enabled but can't attach (pi has no MCP client); preview no longer triggers it.

Test plan

  • cargo fmt --check, cargo clippy --workspace --all-targets -- -D warnings, cargo test --workspace all green (new tests: gate mode matrix, approval mapping incl. shadowed builtins, dialog request/response/cleanup, custom-message display rules, session-options coercion + preview drop, settings round-trips, launch-args ordering, locale parity).
  • Live pi e2e: extension tool confirmed + executed after approval; shadowed read gated instead of auto-allowed; denial honored.

🤖 Generated with Claude Code

Tryanksand others added 7 commits July 30, 2026 15:06
…ing notifications
pi has no MCP client, so the session warning now names which tcode tool
families (preview browser, orchestration, computer-use) are unavailable
instead of a blanket message. Extension ctx.ui.notify calls at warning/
error level now surface as session warnings instead of being dropped,
both in steady state and during the startup handshake.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…via native approval
The gate now resolves tool provenance with pi.getAllTools(): builtins keep
the existing policy, extension/SDK tools are blocked in read_only, allowed
in full_access, and confirmed through tcode's native approval elsewhere.
A tool whose builtin name was shadowed by an extension is treated as an
extension tool, and its approval card maps to ToolUse (never ExecCommand/
FileChange) with the extension path and shadowing noted in the detail.
Tools with unresolvable provenance stay blocked, fail closed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…prove
pi in RPC mode never shows its project-trust prompt, so project-local .pi
extensions/settings/skills were silently ignored. Each pi profile now has
an off-by-default toggle that appends --approve to the launch args after
the profile's configured launch arguments.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Extension select/input/editor dialogs now map onto the native user-input
panel instead of being auto-cancelled: select options become choices,
input placeholders fold into the question, and editor prefill seeds the
free-text field (new optional UserInputQuestion.prefill, additive for
all providers). Pending dialogs are resolved with pi's cancelled
response on turn end, interrupt, cancel, and shutdown, and dialogs
arriving during the startup handshake are auto-cancelled.
Displayed custom messages from pi.sendMessage now appear as Work Log
items keyed by their customType instead of being dropped.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
pi sessions now launch as a bare 'pi --mode rpc' by default: no permission
extension, no TCODE_PI_APPROVAL_MODE env, and no preview MCP registration
(pi has no MCP client to attach it). A new off-by-default per-profile
'Native approvals' toggle opts back into the tcode permission gate, which
is injected only for the modes that need it (supervised and auto-accept
edits); read-only stays on pi's native --tools filter either way.
Without the toggle, stored supervised modes are coerced to full access in
SessionOptions only — the persisted preference survives and resurfaces
when the toggle is enabled — and the approval-mode picker shows the two
supervised entries disabled with a pointer to the provider setting. The
unattached-MCP warning now fires only for explicitly enabled orchestrate
or computer-use registrations, so default pi sessions start silently.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Tryanks
Tryanks enabled auto-merge July 30, 2026 08:06
@Tryanks
Tryanks merged commit 3625823 into mainJul 30, 2026
3 checks passed
@Tryanks
Tryanks deleted the feat/pi-extension-support branch July 30, 2026 08:12
Sign up for freeto 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.

1 participant

@Tryanks
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(pi): support the pi extension ecosystem with zero injection by default - #189

Merged
Tryanks merged 7 commits into
mainfrom
feat/pi-extension-support
Jul 30, 2026
Merged

feat(pi): support the pi extension ecosystem with zero injection by default#189
Tryanks merged 7 commits into
mainfrom
feat/pi-extension-support

Conversation

@Tryanks

Copy link
Copy Markdown
Owner

Summary

Makes user-installed pi extensions first-class inside tcode's pi sessions, while defaulting to zero tcode injection in keeping with pi's minimalism — instrumentation is something the user opts into, not something tcode imposes.

Default experience (respects pi's philosophy)

  • A pi session is now a bare pi --mode rpc: no injected extension, no injection env vars, no preview MCP token minting, no startup toast.
  • Extension-registered tools run natively; extension select/input/editor dialogs surface through the native user-input panel (with editor prefill via a new optional UserInputQuestion.prefill); displayed pi.sendMessage messages appear as Work Log items; extension notify warnings/errors surface as session warnings.

Opt-in toggles on the pi provider card (both off by default)

  • Native approvals — injects the tcode permission gate for supervised / auto-accept-edits modes only. The gate resolves tool provenance via pi.getAllTools(): builtins keep the existing policy; extension tools go through native approval (approval card names the extension path); an extension shadowing a builtin name (read, bash, …) always requires approval and renders as ToolUse, never as a plain shell command; unresolvable provenance stays blocked fail-closed. Without the toggle, stored supervised modes are coerced to full access in SessionOptions only (the persisted preference survives), and the mode picker shows the supervised entries disabled with a pointer to the setting.
  • Trust project extensions — launches pi with --approve so project-local .pi extensions/settings/skills load (pi's RPC mode never shows its interactive trust prompt).

Warning policy

The "MCP tools unavailable" toast now fires only when orchestrate or computer-use were explicitly enabled but can't attach (pi has no MCP client); preview no longer triggers it.

Test plan

  • cargo fmt --check, cargo clippy --workspace --all-targets -- -D warnings, cargo test --workspace all green (new tests: gate mode matrix, approval mapping incl. shadowed builtins, dialog request/response/cleanup, custom-message display rules, session-options coercion + preview drop, settings round-trips, launch-args ordering, locale parity).
  • Live pi e2e: extension tool confirmed + executed after approval; shadowed read gated instead of auto-allowed; denial honored.

🤖 Generated with Claude Code

Tryanksand others added 7 commits July 30, 2026 15:06
…ing notifications
pi has no MCP client, so the session warning now names which tcode tool
families (preview browser, orchestration, computer-use) are unavailable
instead of a blanket message. Extension ctx.ui.notify calls at warning/
error level now surface as session warnings instead of being dropped,
both in steady state and during the startup handshake.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…via native approval
The gate now resolves tool provenance with pi.getAllTools(): builtins keep
the existing policy, extension/SDK tools are blocked in read_only, allowed
in full_access, and confirmed through tcode's native approval elsewhere.
A tool whose builtin name was shadowed by an extension is treated as an
extension tool, and its approval card maps to ToolUse (never ExecCommand/
FileChange) with the extension path and shadowing noted in the detail.
Tools with unresolvable provenance stay blocked, fail closed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…prove
pi in RPC mode never shows its project-trust prompt, so project-local .pi
extensions/settings/skills were silently ignored. Each pi profile now has
an off-by-default toggle that appends --approve to the launch args after
the profile's configured launch arguments.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Extension select/input/editor dialogs now map onto the native user-input
panel instead of being auto-cancelled: select options become choices,
input placeholders fold into the question, and editor prefill seeds the
free-text field (new optional UserInputQuestion.prefill, additive for
all providers). Pending dialogs are resolved with pi's cancelled
response on turn end, interrupt, cancel, and shutdown, and dialogs
arriving during the startup handshake are auto-cancelled.
Displayed custom messages from pi.sendMessage now appear as Work Log
items keyed by their customType instead of being dropped.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
pi sessions now launch as a bare 'pi --mode rpc' by default: no permission
extension, no TCODE_PI_APPROVAL_MODE env, and no preview MCP registration
(pi has no MCP client to attach it). A new off-by-default per-profile
'Native approvals' toggle opts back into the tcode permission gate, which
is injected only for the modes that need it (supervised and auto-accept
edits); read-only stays on pi's native --tools filter either way.
Without the toggle, stored supervised modes are coerced to full access in
SessionOptions only — the persisted preference survives and resurfaces
when the toggle is enabled — and the approval-mode picker shows the two
supervised entries disabled with a pointer to the provider setting. The
unattached-MCP warning now fires only for explicitly enabled orchestrate
or computer-use registrations, so default pi sessions start silently.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Tryanks
Tryanks enabled auto-merge July 30, 2026 08:06
@Tryanks
Tryanks merged commit 3625823 into mainJul 30, 2026
3 checks passed
@Tryanks
Tryanks deleted the feat/pi-extension-support branch July 30, 2026 08:12
Sign up for freeto 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.

1 participant

@Tryanks
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

feat(pi): support the pi extension ecosystem with zero injection by default - #189

Merged
Tryanks merged 7 commits into
mainfrom
feat/pi-extension-support
Jul 30, 2026
Merged

feat(pi): support the pi extension ecosystem with zero injection by default#189
Tryanks merged 7 commits into
mainfrom
feat/pi-extension-support

Conversation

@Tryanks

Copy link
Copy Markdown
Owner

Summary

Makes user-installed pi extensions first-class inside tcode's pi sessions, while defaulting to zero tcode injection in keeping with pi's minimalism — instrumentation is something the user opts into, not something tcode imposes.

Default experience (respects pi's philosophy)

  • A pi session is now a bare pi --mode rpc: no injected extension, no injection env vars, no preview MCP token minting, no startup toast.
  • Extension-registered tools run natively; extension select/input/editor dialogs surface through the native user-input panel (with editor prefill via a new optional UserInputQuestion.prefill); displayed pi.sendMessage messages appear as Work Log items; extension notify warnings/errors surface as session warnings.

Opt-in toggles on the pi provider card (both off by default)

  • Native approvals — injects the tcode permission gate for supervised / auto-accept-edits modes only. The gate resolves tool provenance via pi.getAllTools(): builtins keep the existing policy; extension tools go through native approval (approval card names the extension path); an extension shadowing a builtin name (read, bash, …) always requires approval and renders as ToolUse, never as a plain shell command; unresolvable provenance stays blocked fail-closed. Without the toggle, stored supervised modes are coerced to full access in SessionOptions only (the persisted preference survives), and the mode picker shows the supervised entries disabled with a pointer to the setting.
  • Trust project extensions — launches pi with --approve so project-local .pi extensions/settings/skills load (pi's RPC mode never shows its interactive trust prompt).

Warning policy

The "MCP tools unavailable" toast now fires only when orchestrate or computer-use were explicitly enabled but can't attach (pi has no MCP client); preview no longer triggers it.

Test plan

  • cargo fmt --check, cargo clippy --workspace --all-targets -- -D warnings, cargo test --workspace all green (new tests: gate mode matrix, approval mapping incl. shadowed builtins, dialog request/response/cleanup, custom-message display rules, session-options coercion + preview drop, settings round-trips, launch-args ordering, locale parity).
  • Live pi e2e: extension tool confirmed + executed after approval; shadowed read gated instead of auto-allowed; denial honored.

🤖 Generated with Claude Code

Tryanksand others added 7 commits July 30, 2026 15:06
…ing notifications
pi has no MCP client, so the session warning now names which tcode tool
families (preview browser, orchestration, computer-use) are unavailable
instead of a blanket message. Extension ctx.ui.notify calls at warning/
error level now surface as session warnings instead of being dropped,
both in steady state and during the startup handshake.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…via native approval
The gate now resolves tool provenance with pi.getAllTools(): builtins keep
the existing policy, extension/SDK tools are blocked in read_only, allowed
in full_access, and confirmed through tcode's native approval elsewhere.
A tool whose builtin name was shadowed by an extension is treated as an
extension tool, and its approval card maps to ToolUse (never ExecCommand/
FileChange) with the extension path and shadowing noted in the detail.
Tools with unresolvable provenance stay blocked, fail closed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…prove
pi in RPC mode never shows its project-trust prompt, so project-local .pi
extensions/settings/skills were silently ignored. Each pi profile now has
an off-by-default toggle that appends --approve to the launch args after
the profile's configured launch arguments.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Extension select/input/editor dialogs now map onto the native user-input
panel instead of being auto-cancelled: select options become choices,
input placeholders fold into the question, and editor prefill seeds the
free-text field (new optional UserInputQuestion.prefill, additive for
all providers). Pending dialogs are resolved with pi's cancelled
response on turn end, interrupt, cancel, and shutdown, and dialogs
arriving during the startup handshake are auto-cancelled.
Displayed custom messages from pi.sendMessage now appear as Work Log
items keyed by their customType instead of being dropped.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
pi sessions now launch as a bare 'pi --mode rpc' by default: no permission
extension, no TCODE_PI_APPROVAL_MODE env, and no preview MCP registration
(pi has no MCP client to attach it). A new off-by-default per-profile
'Native approvals' toggle opts back into the tcode permission gate, which
is injected only for the modes that need it (supervised and auto-accept
edits); read-only stays on pi's native --tools filter either way.
Without the toggle, stored supervised modes are coerced to full access in
SessionOptions only — the persisted preference survives and resurfaces
when the toggle is enabled — and the approval-mode picker shows the two
supervised entries disabled with a pointer to the provider setting. The
unattached-MCP warning now fires only for explicitly enabled orchestrate
or computer-use registrations, so default pi sessions start silently.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Tryanks
Tryanks enabled auto-merge July 30, 2026 08:06
@Tryanks
Tryanks merged commit 3625823 into mainJul 30, 2026
3 checks passed
@Tryanks
Tryanks deleted the feat/pi-extension-support branch July 30, 2026 08:12
Sign up for freeto 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.

1 participant

@Tryanks
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(pi): support the pi extension ecosystem with zero injection by default - #189

Merged
Tryanks merged 7 commits into
mainfrom
feat/pi-extension-support
Jul 30, 2026
Merged

feat(pi): support the pi extension ecosystem with zero injection by default#189
Tryanks merged 7 commits into
mainfrom
feat/pi-extension-support

Conversation

@Tryanks

Copy link
Copy Markdown
Owner

Summary

Makes user-installed pi extensions first-class inside tcode's pi sessions, while defaulting to zero tcode injection in keeping with pi's minimalism — instrumentation is something the user opts into, not something tcode imposes.

Default experience (respects pi's philosophy)

  • A pi session is now a bare pi --mode rpc: no injected extension, no injection env vars, no preview MCP token minting, no startup toast.
  • Extension-registered tools run natively; extension select/input/editor dialogs surface through the native user-input panel (with editor prefill via a new optional UserInputQuestion.prefill); displayed pi.sendMessage messages appear as Work Log items; extension notify warnings/errors surface as session warnings.

Opt-in toggles on the pi provider card (both off by default)

  • Native approvals — injects the tcode permission gate for supervised / auto-accept-edits modes only. The gate resolves tool provenance via pi.getAllTools(): builtins keep the existing policy; extension tools go through native approval (approval card names the extension path); an extension shadowing a builtin name (read, bash, …) always requires approval and renders as ToolUse, never as a plain shell command; unresolvable provenance stays blocked fail-closed. Without the toggle, stored supervised modes are coerced to full access in SessionOptions only (the persisted preference survives), and the mode picker shows the supervised entries disabled with a pointer to the setting.
  • Trust project extensions — launches pi with --approve so project-local .pi extensions/settings/skills load (pi's RPC mode never shows its interactive trust prompt).

Warning policy

The "MCP tools unavailable" toast now fires only when orchestrate or computer-use were explicitly enabled but can't attach (pi has no MCP client); preview no longer triggers it.

Test plan

  • cargo fmt --check, cargo clippy --workspace --all-targets -- -D warnings, cargo test --workspace all green (new tests: gate mode matrix, approval mapping incl. shadowed builtins, dialog request/response/cleanup, custom-message display rules, session-options coercion + preview drop, settings round-trips, launch-args ordering, locale parity).
  • Live pi e2e: extension tool confirmed + executed after approval; shadowed read gated instead of auto-allowed; denial honored.

🤖 Generated with Claude Code

Tryanksand others added 7 commits July 30, 2026 15:06
…ing notifications
pi has no MCP client, so the session warning now names which tcode tool
families (preview browser, orchestration, computer-use) are unavailable
instead of a blanket message. Extension ctx.ui.notify calls at warning/
error level now surface as session warnings instead of being dropped,
both in steady state and during the startup handshake.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…via native approval
The gate now resolves tool provenance with pi.getAllTools(): builtins keep
the existing policy, extension/SDK tools are blocked in read_only, allowed
in full_access, and confirmed through tcode's native approval elsewhere.
A tool whose builtin name was shadowed by an extension is treated as an
extension tool, and its approval card maps to ToolUse (never ExecCommand/
FileChange) with the extension path and shadowing noted in the detail.
Tools with unresolvable provenance stay blocked, fail closed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…prove
pi in RPC mode never shows its project-trust prompt, so project-local .pi
extensions/settings/skills were silently ignored. Each pi profile now has
an off-by-default toggle that appends --approve to the launch args after
the profile's configured launch arguments.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Extension select/input/editor dialogs now map onto the native user-input
panel instead of being auto-cancelled: select options become choices,
input placeholders fold into the question, and editor prefill seeds the
free-text field (new optional UserInputQuestion.prefill, additive for
all providers). Pending dialogs are resolved with pi's cancelled
response on turn end, interrupt, cancel, and shutdown, and dialogs
arriving during the startup handshake are auto-cancelled.
Displayed custom messages from pi.sendMessage now appear as Work Log
items keyed by their customType instead of being dropped.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
pi sessions now launch as a bare 'pi --mode rpc' by default: no permission
extension, no TCODE_PI_APPROVAL_MODE env, and no preview MCP registration
(pi has no MCP client to attach it). A new off-by-default per-profile
'Native approvals' toggle opts back into the tcode permission gate, which
is injected only for the modes that need it (supervised and auto-accept
edits); read-only stays on pi's native --tools filter either way.
Without the toggle, stored supervised modes are coerced to full access in
SessionOptions only — the persisted preference survives and resurfaces
when the toggle is enabled — and the approval-mode picker shows the two
supervised entries disabled with a pointer to the provider setting. The
unattached-MCP warning now fires only for explicitly enabled orchestrate
or computer-use registrations, so default pi sessions start silently.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Tryanks
Tryanks enabled auto-merge July 30, 2026 08:06
@Tryanks
Tryanks merged commit 3625823 into mainJul 30, 2026
3 checks passed
@Tryanks
Tryanks deleted the feat/pi-extension-support branch July 30, 2026 08:12
Sign up for freeto 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.

1 participant

@Tryanks
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(pi): support the pi extension ecosystem with zero injection by default - #189

Merged
Tryanks merged 7 commits into
mainfrom
feat/pi-extension-support
Jul 30, 2026
Merged

feat(pi): support the pi extension ecosystem with zero injection by default#189
Tryanks merged 7 commits into
mainfrom
feat/pi-extension-support

Conversation

@Tryanks

Copy link
Copy Markdown
Owner

Summary

Makes user-installed pi extensions first-class inside tcode's pi sessions, while defaulting to zero tcode injection in keeping with pi's minimalism — instrumentation is something the user opts into, not something tcode imposes.

Default experience (respects pi's philosophy)

  • A pi session is now a bare pi --mode rpc: no injected extension, no injection env vars, no preview MCP token minting, no startup toast.
  • Extension-registered tools run natively; extension select/input/editor dialogs surface through the native user-input panel (with editor prefill via a new optional UserInputQuestion.prefill); displayed pi.sendMessage messages appear as Work Log items; extension notify warnings/errors surface as session warnings.

Opt-in toggles on the pi provider card (both off by default)

  • Native approvals — injects the tcode permission gate for supervised / auto-accept-edits modes only. The gate resolves tool provenance via pi.getAllTools(): builtins keep the existing policy; extension tools go through native approval (approval card names the extension path); an extension shadowing a builtin name (read, bash, …) always requires approval and renders as ToolUse, never as a plain shell command; unresolvable provenance stays blocked fail-closed. Without the toggle, stored supervised modes are coerced to full access in SessionOptions only (the persisted preference survives), and the mode picker shows the supervised entries disabled with a pointer to the setting.
  • Trust project extensions — launches pi with --approve so project-local .pi extensions/settings/skills load (pi's RPC mode never shows its interactive trust prompt).

Warning policy

The "MCP tools unavailable" toast now fires only when orchestrate or computer-use were explicitly enabled but can't attach (pi has no MCP client); preview no longer triggers it.

Test plan

  • cargo fmt --check, cargo clippy --workspace --all-targets -- -D warnings, cargo test --workspace all green (new tests: gate mode matrix, approval mapping incl. shadowed builtins, dialog request/response/cleanup, custom-message display rules, session-options coercion + preview drop, settings round-trips, launch-args ordering, locale parity).
  • Live pi e2e: extension tool confirmed + executed after approval; shadowed read gated instead of auto-allowed; denial honored.

🤖 Generated with Claude Code

Tryanksand others added 7 commits July 30, 2026 15:06
…ing notifications
pi has no MCP client, so the session warning now names which tcode tool
families (preview browser, orchestration, computer-use) are unavailable
instead of a blanket message. Extension ctx.ui.notify calls at warning/
error level now surface as session warnings instead of being dropped,
both in steady state and during the startup handshake.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…via native approval
The gate now resolves tool provenance with pi.getAllTools(): builtins keep
the existing policy, extension/SDK tools are blocked in read_only, allowed
in full_access, and confirmed through tcode's native approval elsewhere.
A tool whose builtin name was shadowed by an extension is treated as an
extension tool, and its approval card maps to ToolUse (never ExecCommand/
FileChange) with the extension path and shadowing noted in the detail.
Tools with unresolvable provenance stay blocked, fail closed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…prove
pi in RPC mode never shows its project-trust prompt, so project-local .pi
extensions/settings/skills were silently ignored. Each pi profile now has
an off-by-default toggle that appends --approve to the launch args after
the profile's configured launch arguments.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Extension select/input/editor dialogs now map onto the native user-input
panel instead of being auto-cancelled: select options become choices,
input placeholders fold into the question, and editor prefill seeds the
free-text field (new optional UserInputQuestion.prefill, additive for
all providers). Pending dialogs are resolved with pi's cancelled
response on turn end, interrupt, cancel, and shutdown, and dialogs
arriving during the startup handshake are auto-cancelled.
Displayed custom messages from pi.sendMessage now appear as Work Log
items keyed by their customType instead of being dropped.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
pi sessions now launch as a bare 'pi --mode rpc' by default: no permission
extension, no TCODE_PI_APPROVAL_MODE env, and no preview MCP registration
(pi has no MCP client to attach it). A new off-by-default per-profile
'Native approvals' toggle opts back into the tcode permission gate, which
is injected only for the modes that need it (supervised and auto-accept
edits); read-only stays on pi's native --tools filter either way.
Without the toggle, stored supervised modes are coerced to full access in
SessionOptions only — the persisted preference survives and resurfaces
when the toggle is enabled — and the approval-mode picker shows the two
supervised entries disabled with a pointer to the provider setting. The
unattached-MCP warning now fires only for explicitly enabled orchestrate
or computer-use registrations, so default pi sessions start silently.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Tryanks
Tryanks enabled auto-merge July 30, 2026 08:06
@Tryanks
Tryanks merged commit 3625823 into mainJul 30, 2026
3 checks passed
@Tryanks
Tryanks deleted the feat/pi-extension-support branch July 30, 2026 08:12
Sign up for freeto 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.

1 participant

@Tryanks
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

feat(pi): support the pi extension ecosystem with zero injection by default - #189

Merged
Tryanks merged 7 commits into
mainfrom
feat/pi-extension-support
Jul 30, 2026
Merged

feat(pi): support the pi extension ecosystem with zero injection by default#189
Tryanks merged 7 commits into
mainfrom
feat/pi-extension-support

Conversation

@Tryanks

Copy link
Copy Markdown
Owner

Summary

Makes user-installed pi extensions first-class inside tcode's pi sessions, while defaulting to zero tcode injection in keeping with pi's minimalism — instrumentation is something the user opts into, not something tcode imposes.

Default experience (respects pi's philosophy)

  • A pi session is now a bare pi --mode rpc: no injected extension, no injection env vars, no preview MCP token minting, no startup toast.
  • Extension-registered tools run natively; extension select/input/editor dialogs surface through the native user-input panel (with editor prefill via a new optional UserInputQuestion.prefill); displayed pi.sendMessage messages appear as Work Log items; extension notify warnings/errors surface as session warnings.

Opt-in toggles on the pi provider card (both off by default)

  • Native approvals — injects the tcode permission gate for supervised / auto-accept-edits modes only. The gate resolves tool provenance via pi.getAllTools(): builtins keep the existing policy; extension tools go through native approval (approval card names the extension path); an extension shadowing a builtin name (read, bash, …) always requires approval and renders as ToolUse, never as a plain shell command; unresolvable provenance stays blocked fail-closed. Without the toggle, stored supervised modes are coerced to full access in SessionOptions only (the persisted preference survives), and the mode picker shows the supervised entries disabled with a pointer to the setting.
  • Trust project extensions — launches pi with --approve so project-local .pi extensions/settings/skills load (pi's RPC mode never shows its interactive trust prompt).

Warning policy

The "MCP tools unavailable" toast now fires only when orchestrate or computer-use were explicitly enabled but can't attach (pi has no MCP client); preview no longer triggers it.

Test plan

  • cargo fmt --check, cargo clippy --workspace --all-targets -- -D warnings, cargo test --workspace all green (new tests: gate mode matrix, approval mapping incl. shadowed builtins, dialog request/response/cleanup, custom-message display rules, session-options coercion + preview drop, settings round-trips, launch-args ordering, locale parity).
  • Live pi e2e: extension tool confirmed + executed after approval; shadowed read gated instead of auto-allowed; denial honored.

🤖 Generated with Claude Code

Tryanksand others added 7 commits July 30, 2026 15:06
…ing notifications
pi has no MCP client, so the session warning now names which tcode tool
families (preview browser, orchestration, computer-use) are unavailable
instead of a blanket message. Extension ctx.ui.notify calls at warning/
error level now surface as session warnings instead of being dropped,
both in steady state and during the startup handshake.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…via native approval
The gate now resolves tool provenance with pi.getAllTools(): builtins keep
the existing policy, extension/SDK tools are blocked in read_only, allowed
in full_access, and confirmed through tcode's native approval elsewhere.
A tool whose builtin name was shadowed by an extension is treated as an
extension tool, and its approval card maps to ToolUse (never ExecCommand/
FileChange) with the extension path and shadowing noted in the detail.
Tools with unresolvable provenance stay blocked, fail closed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…prove
pi in RPC mode never shows its project-trust prompt, so project-local .pi
extensions/settings/skills were silently ignored. Each pi profile now has
an off-by-default toggle that appends --approve to the launch args after
the profile's configured launch arguments.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Extension select/input/editor dialogs now map onto the native user-input
panel instead of being auto-cancelled: select options become choices,
input placeholders fold into the question, and editor prefill seeds the
free-text field (new optional UserInputQuestion.prefill, additive for
all providers). Pending dialogs are resolved with pi's cancelled
response on turn end, interrupt, cancel, and shutdown, and dialogs
arriving during the startup handshake are auto-cancelled.
Displayed custom messages from pi.sendMessage now appear as Work Log
items keyed by their customType instead of being dropped.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
pi sessions now launch as a bare 'pi --mode rpc' by default: no permission
extension, no TCODE_PI_APPROVAL_MODE env, and no preview MCP registration
(pi has no MCP client to attach it). A new off-by-default per-profile
'Native approvals' toggle opts back into the tcode permission gate, which
is injected only for the modes that need it (supervised and auto-accept
edits); read-only stays on pi's native --tools filter either way.
Without the toggle, stored supervised modes are coerced to full access in
SessionOptions only — the persisted preference survives and resurfaces
when the toggle is enabled — and the approval-mode picker shows the two
supervised entries disabled with a pointer to the provider setting. The
unattached-MCP warning now fires only for explicitly enabled orchestrate
or computer-use registrations, so default pi sessions start silently.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Tryanks
Tryanks enabled auto-merge July 30, 2026 08:06
@Tryanks
Tryanks merged commit 3625823 into mainJul 30, 2026
3 checks passed
@Tryanks
Tryanks deleted the feat/pi-extension-support branch July 30, 2026 08:12
Sign up for freeto 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.

1 participant

@Tryanks