diff --git a/apps/host-daemon/src/injected-skills.test.ts b/apps/host-daemon/src/injected-skills.test.ts index 4c557d8a6..1009933ed 100644 --- a/apps/host-daemon/src/injected-skills.test.ts +++ b/apps/host-daemon/src/injected-skills.test.ts @@ -131,7 +131,6 @@ describe("injected skill staging", () => { "global-skills", staged.catalogHash, ), - skillNames: ["release-notes"], }); if (!claudeRoot) { @@ -192,7 +191,14 @@ describe("injected skill staging", () => { if (!claudeRoot) { throw new Error("Expected Claude Code skill root"); } - expect(claudeRoot.skillNames).toEqual(["building-bb-apps"]); + await expect( + readFile( + path.join(claudeRoot.localPluginPath, ".claude-plugin", "plugin.json"), + "utf8", + ).then((content) => JSON.parse(content)), + ).resolves.toMatchObject({ + skills: ["./skills/building-bb-apps"], + }); await expect( readFile( path.join(claudeRoot.localPluginPath, "catalog.json"), diff --git a/apps/host-daemon/src/injected-skills.ts b/apps/host-daemon/src/injected-skills.ts index cee671f6d..545ed1cbf 100644 --- a/apps/host-daemon/src/injected-skills.ts +++ b/apps/host-daemon/src/injected-skills.ts @@ -85,7 +85,6 @@ interface WriteStageRootArgs { interface BuildSkillRootsArgs { catalogHash: string; - skillNames: readonly string[]; stageRootPath: string; } @@ -432,9 +431,6 @@ async function writeStageRoot(args: WriteStageRootArgs): Promise { } function buildSkillRoots(args: BuildSkillRootsArgs): AgentRuntimeSkillRoot[] { - if (args.skillNames.length === 0) { - return []; - } return [ { id: `global-skills:${args.catalogHash}:codex`, @@ -445,7 +441,6 @@ function buildSkillRoots(args: BuildSkillRootsArgs): AgentRuntimeSkillRoot[] { id: `global-skills:${args.catalogHash}:claude-code`, providerId: "claude-code", localPluginPath: args.stageRootPath, - skillNames: [...args.skillNames], }, ]; } @@ -499,12 +494,10 @@ export async function stageInjectedSkillSources( dataDir: args.dataDir, trees: sortedTrees, }); - const skillNames = sortedTrees.map((tree) => tree.source.name); return { catalogHash, skillRoots: buildSkillRoots({ catalogHash, - skillNames, stageRootPath, }), }; diff --git a/apps/host-daemon/src/runtime-manager.test.ts b/apps/host-daemon/src/runtime-manager.test.ts index 8e2f22c5b..6f68b356b 100644 --- a/apps/host-daemon/src/runtime-manager.test.ts +++ b/apps/host-daemon/src/runtime-manager.test.ts @@ -371,7 +371,6 @@ describe("RuntimeManager", () => { "global-skills", entry.skillCatalogHash ?? "", ), - skillNames: ["release-notes"], }, ]); }); diff --git a/packages/agent-runtime/src/claude-code/adapter.test.ts b/packages/agent-runtime/src/claude-code/adapter.test.ts index 1ede09e0e..482743843 100644 --- a/packages/agent-runtime/src/claude-code/adapter.test.ts +++ b/packages/agent-runtime/src/claude-code/adapter.test.ts @@ -326,7 +326,7 @@ describe("claude-code provider adapter", () => { expect(resume?.params).toMatchObject({ workflowsEnabled: false }); }); - it("buildCommand thread/start maps skill roots to Claude local plugins and skills", () => { + it("buildCommand thread/start maps skill roots to Claude local plugins without a skills allowlist", () => { const adapter = createClaudeCodeProviderAdapter(); const cmd = adapter.buildCommandPlan({ type: "thread/start", @@ -341,7 +341,6 @@ describe("claude-code provider adapter", () => { id: "bb-cli", providerId: "claude-code", localPluginPath: "/tmp/bb-skills", - skillNames: ["bb-cli"], }, { id: "repo-tools", @@ -357,8 +356,9 @@ describe("claude-code provider adapter", () => { { type: "local", path: "/tmp/bb-skills" }, { type: "local", path: "/tmp/repo-skills" }, ], - skills: ["bb-cli"], }); + // A skills allowlist would hide every skill the user installed themselves. + expect(cmd?.params).not.toHaveProperty("skills"); }); it("buildCommand thread/start includes construction-level workspace-write roots", () => { diff --git a/packages/agent-runtime/src/claude-code/adapter.ts b/packages/agent-runtime/src/claude-code/adapter.ts index ebf0ecb07..911eaf9c8 100644 --- a/packages/agent-runtime/src/claude-code/adapter.ts +++ b/packages/agent-runtime/src/claude-code/adapter.ts @@ -152,7 +152,6 @@ interface ClaudeLocalPluginConfig { interface ClaudeSkillConfigParams { plugins: ClaudeLocalPluginConfig[]; - skills?: string[]; } interface ClaudeSkillConfigEntryArgs { @@ -181,6 +180,12 @@ function buildClaudeSkillConfigEntry( }; } +/** + * Injected skill roots load as local plugins only. Never pass the SDK `skills` + * option here: it is a session-wide allowlist, so listing the injected skills + * would hide and reject every other skill the user has installed (~/.claude, + * plugins, built-ins). Plugin skills are enabled by CLI defaults. + */ function buildClaudeSkillConfigParams( skillRoots: ProviderExecutionContext["skillRoots"], ): ClaudeSkillConfigParams | undefined { @@ -188,19 +193,10 @@ function buildClaudeSkillConfigParams( return undefined; } - const plugins: ClaudeLocalPluginConfig[] = []; - const skillNames: string[] = []; - for (const skillRoot of skillRoots) { - plugins.push(buildClaudeSkillConfigEntry({ skillRoot })); - if (skillRoot.providerId === "claude-code" && skillRoot.skillNames) { - skillNames.push(...skillRoot.skillNames); - } - } - const distinctSkillNames = [...new Set(skillNames)]; - return { - plugins, - ...(distinctSkillNames.length > 0 ? { skills: distinctSkillNames } : {}), + plugins: skillRoots.map((skillRoot) => + buildClaudeSkillConfigEntry({ skillRoot }), + ), }; } diff --git a/packages/agent-runtime/src/claude-code/bridge/__tests__/bridge.test.ts b/packages/agent-runtime/src/claude-code/bridge/__tests__/bridge.test.ts index aafde1378..630ece325 100644 --- a/packages/agent-runtime/src/claude-code/bridge/__tests__/bridge.test.ts +++ b/packages/agent-runtime/src/claude-code/bridge/__tests__/bridge.test.ts @@ -603,7 +603,7 @@ describe("bridge", () => { }); }); - it("passes Claude local plugins and skills through to the session", () => { + it("passes Claude local plugins through to the session", () => { const options = buildSessionOptions( { workflowsEnabled: false, @@ -613,7 +613,6 @@ describe("bridge", () => { permissionEscalation: "ask", permissionMode: "default", plugins: [{ type: "local", path: "/tmp/bb-skills" }], - skills: ["bb-cli"], }, {}, ); @@ -621,7 +620,7 @@ describe("bridge", () => { expect(options.plugins).toEqual([ { type: "local", path: "/tmp/bb-skills" }, ]); - expect(options.skills).toEqual(["bb-cli"]); + expect(options).not.toHaveProperty("skills"); }); it("passes the resolved Claude permission mode through to the session", () => { diff --git a/packages/agent-runtime/src/claude-code/bridge/__tests__/sdk-session.test.ts b/packages/agent-runtime/src/claude-code/bridge/__tests__/sdk-session.test.ts index bf860f9fe..ca689aecf 100644 --- a/packages/agent-runtime/src/claude-code/bridge/__tests__/sdk-session.test.ts +++ b/packages/agent-runtime/src/claude-code/bridge/__tests__/sdk-session.test.ts @@ -170,14 +170,13 @@ describe("SdkSession", () => { ); }); - it("forwards local plugins and enabled skills to the SDK when configured", () => { + it("forwards local plugins to the SDK without a skills allowlist", () => { const onMessage = vi.fn(); const onDone = vi.fn(); const session = new SdkSession( { ...defaultOptions, plugins: [{ type: "local", path: "/tmp/bb-skills" }], - skills: ["bb-cli"], }, onMessage, onDone, @@ -189,10 +188,12 @@ describe("SdkSession", () => { expect.objectContaining({ options: expect.objectContaining({ plugins: [{ type: "local", path: "/tmp/bb-skills" }], - skills: ["bb-cli"], }), }), ); + // The SDK `skills` option is an allowlist: setting it would hide every + // skill the user installed outside bb (~/.claude, plugins, built-ins). + expect(queryMock.mock.calls[0]?.[0]?.options).not.toHaveProperty("skills"); }); it("mirrors the Claude CLI settings cascade so user, project, and local settings all load", () => { diff --git a/packages/agent-runtime/src/claude-code/bridge/commands.ts b/packages/agent-runtime/src/claude-code/bridge/commands.ts index c35c8e0bf..dcebfa4ff 100644 --- a/packages/agent-runtime/src/claude-code/bridge/commands.ts +++ b/packages/agent-runtime/src/claude-code/bridge/commands.ts @@ -25,7 +25,6 @@ const bridgeClaudeLocalPluginSchema = z.object({ const bridgeClaudePluginsSchema = z .array(bridgeClaudeLocalPluginSchema) .optional(); -const bridgeClaudeSkillsSchema = z.array(z.string()).optional(); const dynamicToolSchema = z.object({ name: z.string(), @@ -52,7 +51,6 @@ const claudeCodeCommandSchema = z.discriminatedUnion("method", [ baseInstructions: z.string(), additionalWorkspaceWriteRoots: bridgeAdditionalWorkspaceWriteRootsSchema, plugins: bridgeClaudePluginsSchema, - skills: bridgeClaudeSkillsSchema, permissionMode: claudePermissionModeSchema, permissionEscalation: bridgePermissionEscalationSchema, config: z.record(z.string(), z.unknown()).optional(), @@ -73,7 +71,6 @@ const claudeCodeCommandSchema = z.discriminatedUnion("method", [ baseInstructions: z.string().optional(), additionalWorkspaceWriteRoots: bridgeAdditionalWorkspaceWriteRootsSchema, plugins: bridgeClaudePluginsSchema, - skills: bridgeClaudeSkillsSchema, permissionMode: claudePermissionModeSchema, permissionEscalation: bridgePermissionEscalationSchema, config: z.record(z.string(), z.unknown()).optional(), diff --git a/packages/agent-runtime/src/claude-code/bridge/sdk-session.ts b/packages/agent-runtime/src/claude-code/bridge/sdk-session.ts index cbb2ef093..13f13d906 100644 --- a/packages/agent-runtime/src/claude-code/bridge/sdk-session.ts +++ b/packages/agent-runtime/src/claude-code/bridge/sdk-session.ts @@ -27,7 +27,6 @@ export interface SdkSessionOptions { env?: NodeJS.ProcessEnv; pathToClaudeCodeExecutable?: Options["pathToClaudeCodeExecutable"]; plugins?: Options["plugins"]; - skills?: Options["skills"]; thinking?: Options["thinking"]; /** Flag-tier settings (highest user-controlled tier); BB owns this layer. */ settings?: Options["settings"]; @@ -124,7 +123,6 @@ export class SdkSession { ? { pathToClaudeCodeExecutable: this.options.pathToClaudeCodeExecutable } : {}), ...(this.options.plugins ? { plugins: this.options.plugins } : {}), - ...(this.options.skills ? { skills: this.options.skills } : {}), ...(this.options.thinking ? { thinking: this.options.thinking } : {}), ...(this.options.settings ? { settings: this.options.settings } : {}), }; diff --git a/packages/agent-runtime/src/claude-code/bridge/session-options.ts b/packages/agent-runtime/src/claude-code/bridge/session-options.ts index c28850b0c..0e914e0c3 100644 --- a/packages/agent-runtime/src/claude-code/bridge/session-options.ts +++ b/packages/agent-runtime/src/claude-code/bridge/session-options.ts @@ -21,7 +21,6 @@ export interface BuildSessionOptionsArgs { permissionMode: ClaudePermissionMode; plugins?: Options["plugins"]; reasoningLevel?: ReasoningLevel; - skills?: Options["skills"]; workflowsEnabled: boolean; } @@ -246,7 +245,6 @@ export function buildSessionOptions( ...(flagSettings ? { settings: flagSettings } : {}), ...(pathToClaudeCodeExecutable ? { pathToClaudeCodeExecutable } : {}), ...(params.plugins ? { plugins: params.plugins } : {}), - ...(params.skills ? { skills: params.skills } : {}), ...(sandbox ? { sandbox } : {}), ...(hooks ? { hooks } : {}), ...(additionalDirectories.length > 0 diff --git a/packages/agent-runtime/src/integration.skill-roots.test.ts b/packages/agent-runtime/src/integration.skill-roots.test.ts index dc1a7a09e..5c818b7d2 100644 --- a/packages/agent-runtime/src/integration.skill-roots.test.ts +++ b/packages/agent-runtime/src/integration.skill-roots.test.ts @@ -96,7 +96,6 @@ function createClaudeSkillPlugin( id: skillName, providerId: "claude-code", localPluginPath: pluginDir, - skillNames: [skillName], }; } diff --git a/packages/agent-runtime/src/runtime-skill-roots.test.ts b/packages/agent-runtime/src/runtime-skill-roots.test.ts index 8167c1b05..076ffff41 100644 --- a/packages/agent-runtime/src/runtime-skill-roots.test.ts +++ b/packages/agent-runtime/src/runtime-skill-roots.test.ts @@ -18,7 +18,6 @@ describe("runtime skill roots", () => { id: "claude-root", providerId: "claude-code", localPluginPath: "/tmp/claude-plugin", - skillNames: ["bb-cli"], }, { id: "pi-root", @@ -38,7 +37,6 @@ describe("runtime skill roots", () => { id: "claude-root", providerId: "claude-code", localPluginPath: "/tmp/claude-plugin", - skillNames: ["bb-cli"], }, { id: "pi-root", diff --git a/packages/agent-runtime/src/runtime-skill-roots.ts b/packages/agent-runtime/src/runtime-skill-roots.ts index 500d4d6fe..8bdad26a4 100644 --- a/packages/agent-runtime/src/runtime-skill-roots.ts +++ b/packages/agent-runtime/src/runtime-skill-roots.ts @@ -69,9 +69,6 @@ function normalizeClaudeCodeSkillRoot( id: skillRoot.id, providerId: skillRoot.providerId, localPluginPath: skillRoot.localPluginPath, - ...(skillRoot.skillNames && skillRoot.skillNames.length > 0 - ? { skillNames: [...skillRoot.skillNames] } - : {}), }; } diff --git a/packages/agent-runtime/src/types.ts b/packages/agent-runtime/src/types.ts index 9717bf561..cdedf9602 100644 --- a/packages/agent-runtime/src/types.ts +++ b/packages/agent-runtime/src/types.ts @@ -27,7 +27,6 @@ export interface AgentRuntimeClaudeCodeSkillRoot { id: string; providerId: "claude-code"; localPluginPath: string; - skillNames?: readonly string[]; } export interface AgentRuntimePiSkillRoot {