Repository navigation
Plugins by repository URL: a runnable, isolated agent-proxy prototype #23574
djgilcrease
started this conversation in
Ideas
Replies: 1 comment
|
@t3dotgg, in today's stream, you mention how you are trying to collect the plugin ideas before you decide how you want to implement it. |
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
A working plugin prototype, starting with a feature that should not need to live in core
The agent proxy proposed in #16677 is useful, but it also asks T3 maintainers to own OAuth flows, account pooling, quota APIs, routing strategies, and several model protocols. Those change independently of T3's conversation UI and orchestration.
I built an environment-owned plugin host and moved that unmerged feature into a separate public repository. The proxy installs from its GitHub URL and contributes its settings, Usage view, commands, streaming HTTP endpoint, and supported provider-launch routing through the same public SDK another plugin would use. No existing builtin feature was rewritten as a plugin.
This is a runnable prototype for discussion, not a request to merge a new platform without agreement on its boundaries. There is no upstream implementation PR.
mainat8d3b061121fe65669d5d43d011b48cd3027a4108.What the user does
Open Settings → Plugins, choose the environment, and paste:
The host finds the highest stable semantic-version tag, checks out the selected commit, validates the plugin package, and starts it. There is no marketplace, central catalog, plugin account, or npm installation step. Plugin authors ship their built entrypoint and dependencies in the tagged repository. Package scripts, Git hooks, and submodules are not executed during installation.
Updates are checked daily while the environment runs, or through Check for updates. Checking does not execute a new version. The user explicitly chooses Update. Disable keeps data; Remove unregisters the plugin and clears its managed package, saved data, and namespaced credentials. Manually registered source folders are preserved.
GitHub, nested GitLab, and self-hosted HTTPS Git URLs use the same Git-based mechanism. Private repositories use credentials already available to Git on the environment; tokens do not belong in the URL. Live install/update testing used GitHub; GitLab URL/tag behavior has focused tests.
Install, remove, reinstall, disable/enable, and configure the restart limit — video
Why add a host at all?
The benefit is giving independently maintained features a place to connect without a fork or another feature-specific RPC/UI path in core. A proxy is a demanding example: it needs long-lived state, secrets, HTTP streaming, background quota refresh, UI, and launch integration together. A one-off MCP tool or an external daemon can supply parts of that, but does not by itself give users one environment-owned installation and management flow across T3 clients.
Core maintains a small set of connection points. The plugin author maintains the external service's behavior and release cadence. A broken optional integration can be disabled or removed independently. Users who do not install a plugin do not run its worker or load its feature dependencies into the server process.
This also gives experiments an exit path: prove usefulness as an external repository before deciding whether a capability belongs in the default product. It does not mean authentication, durable orchestration, rendering, or every existing feature should move out of core.
The contract implemented today
/api/plugins/<id>/, with plugin-owned authentication and cancellation.A repository contains a versioned
t3-plugin.jsonand a built JavaScript module implementingT3Plugin. The SDK describes the public contract; it does not expose server services, the database, React components, Electron IPC, or the orchestrator's decider. Too-new API versions and invalid contributions are rejected.Commands are service calls behind thin transports. The host checks the actual command's permission, rather than trusting the permission supplied by a caller. Agents discover opted-in commands through
t3_plugins_list,t3_plugin_read, andt3_plugin_run. A read envelope cannot turn a write command into a read command. Installation/removal are absent from these MCP tools; secret-bearing proxy sign-in/import/key commands are client-only.Plugin views are data. They cannot inject browser JavaScript or add work to transcript rendering. The two current view locations keep the client contract finite. Rich plugin pages would be a separate decision.
The implementation separates package retrieval, serialized lifecycle management, contribution validation/dispatch, and the worker protocol. There is no general filesystem/network/process capability broker to maintain: this first version explicitly installs trusted same-user code. It reuses T3's existing environment permission model for access from clients and agents.
Failure containment is part of the feature
Each plugin runs in its own OS process. It has bounded IPC and concurrent calls, a JavaScript heap limit, startup/handler watchdogs, and a supervisor. An exiting process or stalled event loop is stopped independently. After five failed attempts by default, the plugin stays stopped for that server session until explicitly retried, re-enabled, or updated. The limit is configurable per plugin, from 1 to 100; a minute of stable operation resets the failure counter.
Startup activation runs separately from constructing the environment, so a stalled plugin does not prevent T3 from opening. Plugin operations wait for initialization, which prevents a launch from silently bypassing a not-yet-ready routing hook. A stopped runtime routing hook fails the affected launch closed. Ordinary cancelled view refreshes do not kill the worker; the handler watchdog still catches a real stall.
The UI test deliberately crashed one plugin. It stopped after exactly five attempts while T3 and the healthy proxy remained usable. Changing the limit to three and retrying produced exactly three further attempts.
Crash limit, explicit retry, and continued application use — video
This is trusted-code process isolation, not a hostile-code sandbox. A malicious plugin running as the same OS user can attack files, processes or system resources. No honest implementation should promise that system-wide OOM, intentional same-user attacks, or a runtime vulnerability can never affect T3. The tested guarantee is containment of ordinary worker exits, exceptions, hangs and bounded protocol failures.
WASM could be another worker execution backend later. A V8 isolate by itself is not an OS-process boundary; keeping the process boundary would still be valuable for heap/native-runtime failures. WASM, fuel metering and an OS sandbox are not implemented or claimed here.
The external agent proxy proves the complete path
The proxy repository owns account authorization/import, private credentials, quota collection, closest-reset/round-robin/least-active selection, sticky sessions, failover, key rotation, and streaming model-protocol translation. Its routes cover OpenAI Responses/Chat, Anthropic Messages, and Google generation formats. Settings and Usage are ordinary portable plugin views.
Supported launch integration currently covers Codex agent/text-generation launches, Claude agent environment/text-generation launches, and T3-managed OpenCode. Cursor, Grok, Pi, Muse and ACP/Antigravity driver paths are not claimed to use these hooks. Supporting additional adapters needs an explicit integration and tests; a proxy supporting an upstream model protocol does not imply every T3 provider runtime is connected.
A user can also configure a verified, directly reachable remote proxy URL/key, view its account status, and disconnect it. Environment management travels over T3's normal authenticated connection. Plugin-owned HTTP routes are a different transport: a relay connection does not automatically publish them, and the prototype does not discover a remote proxy automatically.
Secrets are not returned in views. Explicit client key disclosure is masked, copyable, dismissible, and cleared after 30 seconds. The proxy's JSON uploads are bounded to 16 MiB; oversized streams are cancelled with HTTP 413. Existing provider sessions need restarting to pick up routing changes.
Proxy settings, account controls and masked credential handling — video · Remote-client control — video · Usage view — video
I also sent a real Codex request through the installed plugin: model discovery returned eight models, and inference returned HTTP 200 with a completed stream. The temporary validation account was removed afterward. This is stronger evidence than fixture-only protocol tests, but it is not a claim that all six upstream services' current OAuth/account policies have been verified live.
Updates and recovery were exercised against real tags
The actual update test caught a packaging error: v0.1.1's install manifest still declared v0.1.0. The host rejected that package and kept the working installed version. This exposed missing UI error feedback, which is now present in both client implementations. Release CI now checks the package, install manifest and built module agree.
Updating the same installation to v0.1.2 succeeded and retained its account, pool strategy, sticky-idle setting and restart limit. The failed tag was not rewritten. Activation/persistence rollback and daily/manual check scheduling also have focused tests. Package rollback does not undo a plugin's own data migrations; authors still need backwards-compatible storage changes.
Real tag-based update with preserved settings — video
What this borrows from previous attempts
I read RFC #18844 and the earlier work it links. There is substantial prior art here, and process supervision is not a new invention in this branch.
The case for this approach is a concrete external consumer, reproducible repository installation, explicit failure/update recovery, and a finite public API. It is not that every earlier design was wrong, or that a working prototype automatically settles the maintenance tradeoffs.
Which builtins could be plugins?
The full source-based audit separates capabilities possible through today's SDK from missing host boundaries. No builtin was migrated as part of this work.
I would grow the SDK only when another concrete consumer proves a missing boundary. Adding interfaces for every builtin up front would repeat the large-contract problem. The current implementation is intentionally honest about what it cannot yet replace.
Verification and remaining limits
Full commands, source pins, media provenance and exclusions are in the verification receipt. UI captures use synthetic accounts; native quota panels were hidden with the existing filter for the Usage capture. Recordings are cropped to the browser viewport and are not mockups.
The UI pass used T3's Browser panel against isolated Linux state. Native Electron-shell GUI, native mobile GUI, Windows and single-executable packaging have not been exercised. Non-Codex live OAuth/inference and relay-published proxy endpoints are also not claimed. The host checks are targeted; they are not a claim that the full T3 release/CI matrix was run.
What I would like maintainers to decide
Is a persistent environment-owned extension appropriate for capabilities like the agent proxy, beyond provider-launched MCP configuration? Are commands, portable Settings/Usage views, launch preparation and streaming HTTP a reasonable first boundary? Which additional boundary, if any, has a concrete builtin or external consumer worth supporting next?
The branch makes those choices reviewable and testable before asking to land them. I will not open an upstream implementation PR without agreement on the scope. The standalone proxy can continue evolving outside T3 once the agreed host contract exists.
All reactions