Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions apps/host-daemon/src/injected-skills.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,6 @@ describe("injected skill staging", () => {
"global-skills",
staged.catalogHash,
),
skillNames: ["release-notes"],
});

if (!claudeRoot) {
Expand Down Expand Up @@ -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"),
Expand Down
7 changes: 0 additions & 7 deletions apps/host-daemon/src/injected-skills.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ interface WriteStageRootArgs {

interface BuildSkillRootsArgs {
catalogHash: string;
skillNames: readonly string[];
stageRootPath: string;
}

Expand Down Expand Up @@ -432,9 +431,6 @@ async function writeStageRoot(args: WriteStageRootArgs): Promise<string> {
}

function buildSkillRoots(args: BuildSkillRootsArgs): AgentRuntimeSkillRoot[] {
if (args.skillNames.length === 0) {
return [];
}
return [
{
id: `global-skills:${args.catalogHash}:codex`,
Expand All @@ -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],
},
];
}
Expand Down Expand Up @@ -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,
}),
};
Expand Down
1 change: 0 additions & 1 deletion apps/host-daemon/src/runtime-manager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,6 @@ describe("RuntimeManager", () => {
"global-skills",
entry.skillCatalogHash ?? "",
),
skillNames: ["release-notes"],
},
]);
});
Expand Down
6 changes: 3 additions & 3 deletions packages/agent-runtime/src/claude-code/adapter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
Expand All @@ -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", () => {
Expand Down
22 changes: 9 additions & 13 deletions packages/agent-runtime/src/claude-code/adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,6 @@ interface ClaudeLocalPluginConfig {

interface ClaudeSkillConfigParams {
plugins: ClaudeLocalPluginConfig[];
skills?: string[];
}

interface ClaudeSkillConfigEntryArgs {
Expand Down Expand Up @@ -181,26 +180,23 @@ 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 {
if (!skillRoots || skillRoots.length === 0) {
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 }),
),
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -613,15 +613,14 @@ describe("bridge", () => {
permissionEscalation: "ask",
permissionMode: "default",
plugins: [{ type: "local", path: "/tmp/bb-skills" }],
skills: ["bb-cli"],
},
{},
);

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", () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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", () => {
Expand Down
3 changes: 0 additions & 3 deletions packages/agent-runtime/src/claude-code/bridge/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand All @@ -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(),
Expand All @@ -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(),
Expand Down
2 changes: 0 additions & 2 deletions packages/agent-runtime/src/claude-code/bridge/sdk-session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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"];
Expand Down Expand Up @@ -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 } : {}),
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ export interface BuildSessionOptionsArgs {
permissionMode: ClaudePermissionMode;
plugins?: Options["plugins"];
reasoningLevel?: ReasoningLevel;
skills?: Options["skills"];
workflowsEnabled: boolean;
}

Expand Down Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion packages/agent-runtime/src/integration.skill-roots.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@ function createClaudeSkillPlugin(
id: skillName,
providerId: "claude-code",
localPluginPath: pluginDir,
skillNames: [skillName],
};
}

Expand Down
2 changes: 0 additions & 2 deletions packages/agent-runtime/src/runtime-skill-roots.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ describe("runtime skill roots", () => {
id: "claude-root",
providerId: "claude-code",
localPluginPath: "/tmp/claude-plugin",
skillNames: ["bb-cli"],
},
{
id: "pi-root",
Expand All @@ -38,7 +37,6 @@ describe("runtime skill roots", () => {
id: "claude-root",
providerId: "claude-code",
localPluginPath: "/tmp/claude-plugin",
skillNames: ["bb-cli"],
},
{
id: "pi-root",
Expand Down
3 changes: 0 additions & 3 deletions packages/agent-runtime/src/runtime-skill-roots.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,6 @@ function normalizeClaudeCodeSkillRoot(
id: skillRoot.id,
providerId: skillRoot.providerId,
localPluginPath: skillRoot.localPluginPath,
...(skillRoot.skillNames && skillRoot.skillNames.length > 0
? { skillNames: [...skillRoot.skillNames] }
: {}),
};
}

Expand Down
1 change: 0 additions & 1 deletion packages/agent-runtime/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ export interface AgentRuntimeClaudeCodeSkillRoot {
id: string;
providerId: "claude-code";
localPluginPath: string;
skillNames?: readonly string[];
}

export interface AgentRuntimePiSkillRoot {
Expand Down
Loading