Skip to content

Plugin system (1/8): thread ownership#3725

Open
ccdwyer wants to merge 2 commits into
pingdotgg:mainfrom
ccdwyer:wb/01-thread-ownership
Open

Plugin system (1/8): thread ownership#3725
ccdwyer wants to merge 2 commits into
pingdotgg:mainfrom
ccdwyer:wb/01-thread-ownership

Conversation

@ccdwyer

@ccdwyer ccdwyer commented Jul 6, 2026

Copy link
Copy Markdown

What Changed

Adds projection_threads.owner (default 'user', migration 033) so that agent threads created by plugins are attributable and can be filtered out of user-facing surfaces. User-facing snapshots / lists / relay / the live shell stream filter to user-owned threads; the command read model deliberately sees every thread (the decider must, to validate and replay). Nothing plugin-specific ships in this part — it stands on its own.

Extending t3code today means forking it. This is part 1 of 8 of a small, dependency-ordered stack that adds a runtime plugin system: install third-party features (server + web/Electron) at runtime behind curated, capability-scoped host APIs — no fork required. Thread ownership is the foundation: once plugins can spawn agent threads, those threads need to be attributable so they don't pollute the user's thread list. This piece is useful and mergeable on its own even if none of the later parts land.

A deliberate goal here is to take pressure off the core. Right now, anyone who wants to customize t3code has to fork it or try to land their feature upstream — which is exactly the stream of unwanted-feature PRs this repo asks people not to open. A plugin system gives that energy somewhere else to go: contributors ship their customizations as installable plugins instead of PRs, so maintainers field fewer feature requests they have to decline and the core stays lean. The intent is to make this the last large feature you have to review — after it, most "can you add X" turns into "ship X as a plugin."

The full project — which parts deliver what

The repo asks for small, focused PRs, so the plugin system is submitted as 8 dependency-ordered PRs. Merge bottom-up (each later part's diff is cumulative against main until its parent merges — GitHub can't base a fork PR on a fork branch; parts 2–8 are drafts blocked on their parent):

Part PR Delivers Builds on
1 this thread ownership (standalone)
2 #3726 plugin host lifecycle + @t3tools/plugin-sdk 1
3 #3727 WS RPC transport + plugin-aware auth scopes 2
4 #3728 mechanical capability façades (db/secrets/env/projections/textgen/sourcecontrol/terminals/http) 3
5 #3729 agents + vcs capabilities 4
6 #3730 web host + extension points (routes/sidebar/settings/palette) 5
7 #3731 marketplace + install lifecycle + settings UI + fixture 6
8 #3732 filesystem/httpClient capabilities + hardening 7

Feature → parts that must be merged:

  • Run a server-side plugin (RPC in/out): parts 1–4
  • Give it agent / git capabilities: + 5
  • Plugins that contribute web UI: + 6
  • Install plugins from a marketplace source (consent, sha256, safe-extract): + 7
  • Filesystem / outbound-HTTP capabilities (with SSRF guard): + 8 (full system)

Example plugin

These APIs are proven by porting a substantial existing feature — a board-as-state-machine workflow engine, 46 RPC methods — into a standalone installable plugin built entirely on the capabilities in this series: 👉 https://github.com/ccdwyer/workflow-boards-plugin (distributed separately, not in these PRs).

Review

Beyond the automated PR bots, every part was reviewed pre-submission by a four-model tribunal — GPT-5.5, Grok, GLM-5.2, and Fable — each reading the slice's final content and tracing execution rather than the diff alone, which surfaced a batch of real issues (SSRF-via-redirect, a credential leak, a cross-client visibility leak, an interrupt-safety bug, and ~25 more) that are all fixed. Findings addressed in this part:

  • Live shell-stream leak (MUST): subsequent thread events pushed plugin threads to every connected client (only the initial snapshot was owner-filtered) → owner-guarded, fails closed.
  • thread.create owner-trust (MUST): a client could forge a hidden plugin-owned thread → the client-facing wire union now uses an owner-less command; owner is server-injected only.
  • Command-read-model latestTurn rehydration gap + owner-grammar drift.

UI Changes

N/A — this part is server + contracts only.

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes (no UI in this part)
  • I included a video for animation/interaction changes (N/A)

https://claude.ai/code/session_011H86UHL1RPuWBX3LBTUPsk

Threads carry an owner (user or plugin:<id>); plugin-owned threads are
hidden from user-facing projections, activity relays, and client thread
state. Includes migration 033 and the decider/projector/read-model wiring.

Claude-Session: https://claude.ai/code/session_011H86UHL1RPuWBX3LBTUPsk
@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 9b0bffaf-8c70-4c87-8ac7-66cbbedf1a5b

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Comment thread packages/contracts/src/orchestration.ts

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 5f24c87. Configure here.

Comment thread packages/contracts/src/orchestration.ts
@macroscopeapp

macroscopeapp Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

Foundational PR for plugin system (1/8) introducing thread ownership concept, new database schema, filtering logic to hide plugin threads from user views, and relay integration. New feature infrastructure warrants human review.

You can customize Macroscope's approvability policy. Learn more.

Clients could send thread.create with owner=plugin:* via the client wire
union and forge a hidden thread. Add an owner-less ClientThreadCreateCommand
and use it in the client-facing unions; owner stays server-injected.

Claude-Session: https://claude.ai/code/session_011H86UHL1RPuWBX3LBTUPsk
@ccdwyer

ccdwyer commented Jul 6, 2026

Copy link
Copy Markdown
Author

Fixed in wb/01 (force-pushed): thread.create no longer accepts a client-set owner. Added an owner-less ClientThreadCreateCommand to the client-facing wire unions (ClientOrchestrationCommand / DispatchableClientOrchestrationCommand); owner stays server-injected by the agents capability and defaults to "user" in the decider, so a client can no longer forge a hidden plugin-owned thread. The later parts already carried this fix; the stack was rebased to keep it consistent.

https://claude.ai/code/session_011H86UHL1RPuWBX3LBTUPsk

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant