Repository navigation
Conversation
This was referenced Oct 30, 2026
Open
…bility flag Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PluginHost discovers installed and dev plugins, loads enabled CommonJS entries after the server is listening, and hands each a Promise-based API for logging, settings, storage, RPC methods and channels. Failures mark the plugin failed and never stop the server. Settings live beside T3's state with secrets in the server secret store; storage is a lazily opened SQLite file. Eight plugins.* WebSocket methods manage plugins, and the environment advertises plugins: true. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An adversarial review found that reloading one plugin left plugins whose folders vanished running, that a caller disconnecting mid-disable left a plugin half torn down but still routed, that a misspelled access level made a write method callable by read-only sessions, and that reload kept old code for symlinked plugin folders. Lifecycle changes now run in the host's scope, vanished plugins are stopped, access must be read or write, and discovery resolves real paths. Activation and cleanups get deadlines, calls stop routing before teardown, and plugins.json keeps unknown keys. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Settings gains a Plugins page for the selected environment: each plugin with its status, failure, enable switch and reload, plus a settings form generated from the manifest's JSON Schema with write-only secret fields and a JSON fallback. The page follows plugins.subscribeStates only while open; the form model lives in client-runtime for the later mobile screen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ng and send hooks Plugins can now follow stored orchestration events by type, read and act on threads and projects, run scheduled work, see and extend outgoing messages before they are sent, offer MCP tools to agents and serve HTTP routes under /api/plugins/<id>, and read the server's version, descriptor and redacted settings. The send hook runs in ThreadManagementService.dispatch with a 2 s deadline and fails open; with no hooks it is one Ref read. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… writes An adversarial review found that a send hook appending to /goal clear turned it into setting a goal, that the SDK promised a veto nothing honoured, that several event types merged out of sequence order, that a schedule could outlive its plugin, and that plugin write tools skipped the caller's mode limits. Hooks now skip slash commands, veto is gone from the SDK, multi-type event streams stay ordered, schedules and hooks stop on the deactivation signal, API calls end after cleanups, plugin write tools need full access like environment writes, and tool schemas must be objects. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ashx-j
force-pushed
the
feat/plugins-phase-3
branch
from
October 31, 2026 21:32
17a61b1 to
c2d9362
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Phase 3 of the plugin system roadmap (#3, phase issue #7). It builds on #16, so until #14 to #16 merge this diff also shows their commits.
After Phase 1 a server plugin could store data and answer calls, but it couldn't see or touch anything else in T3. This phase gives plugins most of what T3's own server features use, through the same Promise-based API:
events.stored({ types, afterSequence? })follows stored orchestration events of the requested types, from now or from a sequence number. The server opens one type-filtered stream per requested type, so other events never reach the plugin.threads.list / read / sendMessage / interrupt / renameandprojects.list / readgo throughThreadManagementServiceand the project store, the same paths as the app.turns.beforeDispatch(hook)sees each user or agent message, except slash commands, before it is sent and can append context. It runs inThreadManagementService.dispatch, never in the orchestrator, with a 2-second deadline. A hook that is slow or throws is skipped and the message goes through.mcp.registerTooloffers a tool to agents asplg_<pluginId>_<name>. Read tools work for read-only MCP sessions, and write tools are checked like built-in writes. After a plugin is disabled its tools answer "plugin disabled", because MCP can't remove a tool. At3_plugins_listtool appears only once a plugin is installed, so users without plugins don't pay context for it.http.route(method, path, handler)serves routes under/api/plugins/<pluginId>/with the same sign-in as the rest of/api. GET needs read access, other methods need operate access. Plugins never see the caller'sauthorizationorcookieheaders, and request bodies are capped at 1 MiB.schedule.every(ms, handler)runs scheduled work until the plugin is disabled.server.version,server.environment()andserver.settings()(redacted) expose server info.Fixes from an adversarial review (a second Claude Opus 5.5 read the first version, commit
17a61b157b):/goal clearinto setting a new goal, and stopped/compactfrom matching. The dispatch test covers it.vetoresult, because nothing honoured it. Veto is planned for Phase 5.writeMCP tools now need the same access as environment writes: a full-access/default calling thread or client. Their handlers can't see the caller's mode limits, so a plan-mode agent could otherwise reach anything the plugin can do.type: "object", because model APIs reject anything else and that would fail every turn.Changes from the roadmap (issue #7 is updated with the reasons):
notify. A notification item can't be recorded without starting an agent run, and adding a command for it means changingOrchestrator.ts.text.generateandregisterTitleGenerator.TextGenerationhas no free-form method.secrets.request. Asking the user for a secret is a thread-scoped MCP flow.threads.create,threads.setMetadata,worktrees.list,schedule.atandevents.pluginState.secrets.getisn't needed, becausesettings.get()already returns the plugin's own secret values.dispatch, which every caller handles.schedule.everyruns as a fiber per plugin call instead of usingScheduler.Measurements:
Refread, about 0.27 µs per message. A micro-benchmark measured 356 ns against an 89 nsEffect.succeedbaseline. Dispatching a message involves a database transaction, so this is noise.thread.metadata-updatedevent that its rename produced.AgentContextBudget.test.tspasses with no change toagentContextBudget.json.Test plugins:
workbench-pluginuses threads, projects, events, schedule, the send hook and server info.mcp-pluginhas a read toolechoand a write tooltouch.http-pluginservesGET /helloandPOST /echo.Verification:
PluginHost.test.ts(11 cases, including one that loadsworkbench-plugin),PluginMcpTools.test.ts,PluginHttpRoutes.test.ts,api/turns.test.ts(a throwing hook and a hook that never resolves are both skipped) andThreadManagementService.test.tspass. The newThreadManagementService.test.tscase shows a hook appending to a user message but not to a notification.McpHttpServer.test.ts,McpToolAccess.test.tsandAgentContextBudget.test.tspass, andvp run check:changedpassed.GET /api/plugins/http-plugin/helloreturned200 hello worldwith a token and401without one.thread.metadata-updatedevent, at sequence 95170, to the plugin's own event stream.mcp-tool-useeval for thet3_plugins_listdescription, for the same reason.The MCP tools and HTTP routes were written by a Claude Opus 5.5 subagent in parallel with the rest.
PR filed by Claude Opus 5.5 in Claude Code through T3 Code.