Skip to content

feat: port upstream skills and Tools settings (#17691) - #39

Merged
riccardovandra merged 38 commits into
mainfrom
feat/global-skills-port
Oct 23, 2026
Merged

riccardovandra merged 38 commits into
mainfrom
feat/global-skills-port

Conversation

@riccardovandra

Copy link
Copy Markdown
Owner

Problem

The fork has no way to see, install, update or remove skills across projects and providers. Upstream's open PR pingdotgg#17691 adds that as Settings → Tools, but it also brings its own MCP servers store and injection, which overlaps the fork's MCP hub (Settings → MCP Servers).

What was merged

upstream/t3code/skills-installer (36 commits) is merged as-is (no squash, no rewrite), so the daily upstream sync stays clean once pingdotgg#17691 lands. It adds:

  • Settings → Tools → Skills: list per environment/project, on/off switches, Add skills from owner/repo / git URL / folder (bundled skills@1.7.1 CLI), Update, Remove, Copy to other environments, skill file viewer.
  • Skill switches reach Claude, Codex and OpenCode 1.x sessions; the composer hides disabled skills.
  • tools MCP toolkit for agents: t3_tools_read, t3_tools_update, t3_skills_install, t3_skills_remove.
  • RPCs skills.inspect|preview|install|update|remove|export|import and mcpServers.listTools.

How conflicts were resolved (28 files)

  • Auth: RpcAuthorization.layer(scopes, currentSettings, onAuthorized) keeps the fork's analytics hook and upstream's settings-aware scope check; projectsMutate scoping kept.
  • ws.ts / server.ts / McpHttpServer.ts: fork RPCs (FORK_RPC_METHODS), projectsListIgnoredFiles, the override sweep, Docs/AI PM/MCP hub toolkits all kept; skills handlers, SkillLibrary and McpServerTools layers added. T3_MCP_TOOLKITS also lists the fork's Docs, AI PM and MCP servers toolkits. The tools toolkit gets ThreadCommandExecutor like the environment toolkit.
  • serverSettings.ts: upstream's MCP secret handling (redact, materialize, plan, copy-on-rename) applied on top of the fork's newer mapSettingsSecrets structure; updateSettingsWith added.
  • Contracts: settings keep providerInstances plus upstream's mcpServers / disabledSkills project overrides. The fork hub's McpServerName/Transport/Config were renamed McpHub* because upstream's agentTools.ts exports the same names.
  • Adapters (Claude, Codex, ACP, Cursor, OpenCode 2): each session now carries both upstreamServers (fork hub, via T3's forwarding route, withheld in read-only sandboxes) and tools (upstream servers + disabled skills). Claude adopts upstream's ${T3_CODE_MCP_AUTHORIZATION} env reference, now also used for hub servers, so no bearer token sits in process args. Codex keeps the fork's dotted mcp_servers.<name> keys. OpenCode keeps t3-mcp-* hub registrations and adds t3u-* Tools registrations with matching deny/allow rules.
  • Web: upstream's settings-aware scope checks applied to the fork's useSettings / useScopedSettings; composer skill filtering written without manual memo (React Compiler file).
  • Upstream code that targets modules renamed on main since the PR branched (@t3tools/shared/hostProcess → HostProcess, EnvironmentServerConfig, shouldShowInstanceBadge needing enabled) was adapted.
  • apps/server/src/mcp/toolkits/worktree/registration.test.ts stays deleted (upstream main deleted it in test: delete 11k low-signal tests so CI runs faster and flakes less pingdotgg/t3code#22557).

MCP overlap

The two systems are separate stores (mcp-servers.json hub vs settings.mcpServers) with separate injection paths, so they don't double-inject unless the same server is added to both. To keep one place to manage servers, the fork hub stays the authority:

  • The Tools page's MCP servers tab, its server pages and the #tools-mcp-servers search link redirect to Settings → MCP Servers (route-level, settings.tools.tsx). The duplicate search entry is removed.
  • t3_tools_read / t3_tools_update descriptions point agents to mcp_servers_list / mcp_server_set_enabled for hub servers.
  • Upstream's settings.mcpServers plumbing stays in place (empty in practice) so future syncs don't conflict. docs/user/tools.md points to the MCP Servers guide.

Verification

  • PR tests: SkillLibrary, toolsSettings.logic, agentTools, tools/handlers, McpServerTools: 42/42 pass.
  • Fork tests in conflicted areas (RpcAuthorization, serverSettings, McpHttpServer, mcpHub OAuth/Registry, Claude/Codex/OpenCode2 adapters, ProviderSessionManager, ws, Manager, client-runtime mcpServers, commandPermissions, contracts/shared settings, ACP/Cursor): 653/653 pass after updating from origin/main.
  • Typecheck clean for server, contracts, shared, client-runtime and the providers. Web has one error in ChatView.tsx:1908, which also fails on a clean origin/main.
  • Failures that also happen on a clean origin/main: 6 OpenCode2OrchestratorV2.integration tests (timeouts) and McpUpstreamRoute "runs a stdio server with its secret environment".
  • Lint: the PR's files break newer upstream rules (no-manual-memo, prefer-effect-fn, no-test-timeout), and the fork's mcpHub files have their own existing lint errors. Upstream PR code was left untouched to keep the sync clean.

Done by Claude Opus 5.5 in Claude Code (T3 Code).

🤖 Generated with Claude Code

juliusmarminge and others added 30 commits October 8, 2026 00:04
Adds a Tools settings page with Skills and MCP servers tabs, scoped to
environments and projects like other settings.

- MCP servers added in T3 are injected into every provider session next to
  the t3-code server (Claude, Codex, Cursor, OpenCode 1/2, Grok and ACP
  agents). Sensitive env/header values live in the secret store.
- Skills can be switched off by name; Claude, Codex and OpenCode 1.x hide
  them from the session, and the composer drops them from its menu.
- Projects override servers and skill switches per name instead of
  replacing the environment's list.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main moved per-thread MCP config into the McpProviderSessions service and
the ACP adapter into packages/provider-acp. The user's tools now ride on
that service's config, and the adapters read them from the session they
are handed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
claudeMcpQueryOverrides built the skillOverrides settings, but the turn
never handed them to makeClaudeQueryOptions, so a skill switched off in
Settings → Tools still loaded in Claude sessions. Found by running a real
Claude turn; the new test opens a turn and checks the query options.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Renaming an MCP server or variable keeps its stored secret: the client
  sends where it was saved and the server moves it. A sensitive value
  hand-edited into settings.json moves into the store on the next save.
- Turning a secret off and on again with nothing typed keeps it.
- Editing a server at All environments no longer copies it, without its
  secrets, onto environments that never had it; adding one checks names
  across every environment.
- A settings-only client can change a project's skills or switches when
  the project has its own servers: resending a server unchanged is not a
  provider change.
- Environment server switches need provider management, like the server.
- OpenCode 2 always denies other threads' user servers and retries ones
  that failed to register. OpenCode 1 and 2 give an external server the
  user's servers, and OpenCode 1 reapplies skill rules on resume and
  rollback.
- ACP agents get an absolute command for bare names like npx.
- The composer hides disabled skills from slash commands too, a project
  switch for a server named like an object property is ignored, and a
  search for MCP servers opens that tab.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The SDK passes mcpServers to the CLI as an inline --mcp-config argument,
which any local user can read. A sensitive env value or header from
Settings → Tools now goes into the child's environment and --mcp-config
carries a ${VAR} reference, the same as T3's own token since pingdotgg#17408.
Checked against claude 2.1.292: a stdio server received the expanded value.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…skills by scope

- Secret copies read every source before anything is written, so swapping
  two variable names no longer leaves both with one value.
- A repository skill under a folder named plugins stays in Repository; the
  plugins path only classifies skills a provider reports without a scope.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Two sensitive entries with the same name made the second reference point
at the first one's placeholder. Each name now gets one reference holding
its last value, matching how the variable record resolves duplicates.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s that ask

The user's servers were added to Claude's allowedTools, which skips the
permission prompt in approval-required and auto-accept sessions. Full
access already runs them without asking, so the allow rule only bypassed
the modes that ask. Their tools now go through the session's approval.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds a hidden `t3 skills-cli` subcommand that runs the pinned skills CLI
(vercel-labs/skills 1.7.1, telemetry off) and a SkillLibrary service with
preview, install, update, remove and inspect, exposed as skills.* RPCs.
Installs land where `npx skills` puts them, with links for agents that
read only their own folder, chosen from a per-agent folder table.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ge Tools

Settings → Tools → Skills gets Add skills (preview a source's skills, then
install them at the current scope), groups installed skills under the
source they came from with one switch, marks conflicting copies of a name,
and adds View files, Update and Remove to each skill's menu. Agents get
t3_tools_read, t3_tools_update, t3_skills_install and t3_skills_remove.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- remove: the skills CLI exits 0 when it can't delete a skill, so check the
  folder and lock entry afterwards and report the failure.
- update: follow the CLI's own update source rules, using a GitLab or git
  lock's recorded URL and full-depth discovery when a source can't take a
  folder.
- Show a per-skill update failure, and lock the source field while finding.
- t3_tools_update builds its patch inside the settings write lock
  (updateSettingsWith), so a concurrent change isn't overwritten.
- Project skill switches match names ignoring case, like the environment's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ling

- install, update and remove share a lock: each skills CLI run rewrites a
  whole lock file, so two at once could drop each other's entries.
- A project skill switch is written with the environment's spelling of
  the name.
- The CLI child gets the host environment it resolved (HostProcessEnvironment)
  rather than the process's own, so tests run it against their temp home.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ny skill name

- A global install, update or remove now rescans every project an agent has
  listed, since a project's skill list includes the global skills.
- Project skill switches use a null-prototype map, so a skill named
  __proto__ gets a switch like any other.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- After a skill change, agents that list the same folder rescan it one
  after another: a fresh scan drops the others' snapshots of that folder,
  and the registry discards a scan whose starting snapshot changed.
- mcpServerEnabledPatch reads only own keys, so `constructor` isn't taken
  for an inherited server.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ports the Skills UI from n0mahd's skills series (pingdotgg#17513) onto the Tools page:
- dense one-line rows, sections with counts and a hint ('This project · 2
  · Lives in this repo'), ✦ when every agent loads a skill;
- installed packs as collapsible 'From owner/repo' groups with one switch
  and the first three skills shown;
- a Needs attention filter (conflicts, and project or global skills an
  enabled agent doesn't load);
- a skill page replacing the View files dialog: Used by chips, the source,
  Includes scripts with the script files, Copy path, Update and Remove, a
  file tree with script labels, SKILL.md rendered or as source, each copy
  of a conflicting name, and Escape back to the list.

The server marks each file as a script, so the list and the tree agree.
After an install, one agent rescans a project fresh and the rest follow
without dropping its result, so every agent's list shows the new skill.

Co-Authored-By: n0mahd <39080654+n0mahd@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The CLI matches --skill against a skill's SKILL.md name and keys its lock
files by it, but installs into that name sanitized as a folder (`Git
Review` -> `git-review`). Preview now returns the CLI's name with the
folder, and inspect, update and remove find a lock entry by either form.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lts whole

- The Add skills dialog ticks at most 200 skills, the most one install
  takes, says so for a bigger source, and the agent tool shares the limit.
- The skills CLI prints its --json result and exits at once, so a result
  over 64 KiB was cut short in the pipe and the preview failed. The
  subcommand now exits only after stdout drains.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…cking

Deferring process.exit until stdout drained let the CLI's code run on
past an exit it relied on: `add --list` returned into the install path.
A blocking stdout pipe writes everything before the next statement, so
process.exit stays immediate and nothing is cut.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The skill page drew its own Skills / section crumb under the scope picker.
The open skill now lives in the URL (?skill=), so the settings header reads
Settings / Tools / <skill>, with Tools leading back to the list.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…p pack rows

At All projects, Codex's own skill list (read in the folder T3 was launched
from) filled a This project section that belonged to no picked project.
Project skills now come only from a scan of the picked checkout.

Skills inside a From <source> pack, and its N more row, now start where the
pack's name does instead of under its icon.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A pack's skills now line up with every other row. Its From <source> heading
is a slim tinted band whose switch and chevron sit in the rows' columns.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The tabs, search and buttons took three rows above the list. Each tab now puts
the tabs at the start of its own toolbar: search, the attention filter,
rescan and Add skills on Skills; Add server on MCP servers.

Needs attention becomes a warning icon with its count, shown only when
something needs a look, and its tooltip says what that means.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Not available to Claude gave nothing to act on: the agent chips already show
who loads a skill, and nothing in T3 makes another agent load it. Only a name
used by different skills needs a look now, and its message says what to do.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ilter

Each skill in the Add skills picker took three lines, so a big source showed
three at a time. Rows now match the Skills list: name and one-line
description, a script mark, and the file count on the right. A header box
selects or clears every skill shown, and a source with many skills gets a
filter.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Hovering a description that ends in an ellipsis, in the Skills list or the
Add skills picker, shows the full text. The fit is checked as the tooltip
opens, so a line that fits shows none and the lists measure nothing until
hovered.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Remove only reached skills the skills CLI had installed, so most of a
skill folder could be switched off but not deleted. A skill's menu now has
Remove for any copy an agent finds directly in its own skill folders, at
home or in the project. One the CLI installed still goes through the CLI;
another is deleted from each folder an agent reports for it, links first,
along with the folder a link points to when that is one of the user's own.
Plugin and built-in skills stay switch-only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copy path sat in the skill's menu, away from the path it copies. It is now
an icon button after the folder path, for whichever copy is shown, and turns
into a check once copied. The menu keeps Update and Remove.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With Copy path beside the path, the skill's menu held one or two items. They
are now buttons on the skill's page: Update for a skill installed from a
source, and Remove.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
juliusmarminge and others added 8 commits October 10, 2026 22:43
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every agent session gets the t3-code server, but the MCP servers tab only
listed servers added there, so it looked like T3's tools weren't given at
all. It now heads the list as a built-in server with a switch that is on and
locked, since nothing turns it off.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With several environments in scope, the Skills tab read only the primary
environment, so a skill on one machine but not another looked the same.
It now reads every environment in scope and merges their skills by name.
A row shows the machines that have the skill, or one fleet mark when they
all do; its page lists them and can copy the skill to the ones missing it.

A copy goes through two new RPCs. skills.export packs the folder an agent
reports for the skill (bounded at 4 MiB and 500 files). skills.import
reinstalls from the skill's remote source when the CLI recorded one, so the
copy can be updated, and otherwise writes the files into .agents/skills
with links for agents that read their own folder. Update and Remove on a
skill's page now reach every environment in scope that has it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Settings → Tools listed MCP servers but couldn't show what each one offers.
`mcpServers.listTools` starts the named server the way an agent session
would, with the project's overrides and the stored secrets, asks it for
`tools/list` (following cursors), and stops it again, within 30 seconds.
Command servers run in the project's checkout with the host environment
under their own variables; URL servers fall back to SSE on a 404/405.
Failures come back as a typed McpServerToolsError with a plain message.

T3's own `t3-code` server is described from the toolkits `/mcp` registers,
without starting anything; a registration test keeps that list in step.

Listing runs the server's command with its secrets, so it needs
`providers:manage`, the scope that gates adding that command.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Clicking a server on the MCP servers tab, including the built-in t3-code
row, opens its page in place of the list, the way a skill opens: the
header reads Settings / Tools / <server>, and the Tools crumb or Escape
goes back. The page shows the transport and command or URL, the switch,
Edit and Remove as buttons, then the server's tools in dense rows that
open to their parameters (name, type, required, description).

Tools load through `mcpServers.listTools`, with a delayed skeleton, an
error with Retry, and a refresh; an edit while the page is open lists
them again. A server that is switched off can still be inspected. The
row's switch, Reset and menu keep their clicks to themselves.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bring in pingdotgg#17691 (Settings → Tools: skills install,
update, remove, copy to environments, the tools MCP toolkit) and keep
the fork's MCP hub authoritative for MCP servers: the Tools page's
MCP servers tab opens Settings → MCP Servers, hub and Tools servers
both reach every provider adapter, and the fork's hub contract types
are renamed McpHub* to avoid clashing with upstream's agentTools.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to 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.

2 participants