From 84d5e1fa603f647ee3790419c6ea150dc2e89acd Mon Sep 17 00:00:00 2001 From: Arnav Naval Date: Sat, 9 May 2026 10:36:15 -0500 Subject: [PATCH] =?UTF-8?q?[arnav]=20disable=20Claude=20Code's=20bundled?= =?UTF-8?q?=20plugin=20skills=20in=20agent=20sessions=20Pass=20`skills=3D[?= =?UTF-8?q?]`=20to=20ClaudeAgentOptions=20so=20the=20SDK's=20built-in=20pl?= =?UTF-8?q?ugin=20skills=20(/init,=20/review,=20/security-review,=20/simpl?= =?UTF-8?q?ify,=20/loop,=20/schedule,=20/update-config,=20/keybindings-hel?= =?UTF-8?q?p,=20/fewer-permission-prompts,=20/claude-api)=20are=20hidden?= =?UTF-8?q?=20from=20the=20model=20and=20rejected=20by=20the=20Skill=20too?= =?UTF-8?q?l.=20These=20skills=20are=20inappropriate=20in=20OpenSwarm:=20h?= =?UTF-8?q?alf=20mutate=20~/.claude=20config=20files=20(settings.json,=20k?= =?UTF-8?q?eybindings.json)=20that=20OpenSwarm=20doesn't=20read,=20and=20t?= =?UTF-8?q?he=20rest=20expose=20slash=20commands=20the=20backend=20never?= =?UTF-8?q?=20intercepts=20=E2=80=94=20causing=20the=20model=20to=20falsel?= =?UTF-8?q?y=20claim=20capabilities=20it=20can't=20actually=20use.=20OpenS?= =?UTF-8?q?warm's=20own=20skills=20system=20injects=20skill=20content=20di?= =?UTF-8?q?rectly=20into=20the=20user=20prompt=20via=20=5Fresolve=5Fattach?= =?UTF-8?q?ed=5Fskills,=20bypassing=20the=20Skill=20tool=20entirely,=20so?= =?UTF-8?q?=20user-attached=20skills=20are=20unaffected.=20Also=20adds=20a?= =?UTF-8?q?=20regression=20test=20that=20pins=20the=20`skills=3D[]`=20assi?= =?UTF-8?q?gnment=20so=20it=20can't=20be=20silently=20dropped=20in=20a=20f?= =?UTF-8?q?uture=20refactor.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/apps/agents/agent_manager.py | 14 ++++++++++++++ backend/tests/test_agent_manager_unit.py | 20 ++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/backend/apps/agents/agent_manager.py b/backend/apps/agents/agent_manager.py index 7170e530..69aff20c 100644 --- a/backend/apps/agents/agent_manager.py +++ b/backend/apps/agents/agent_manager.py @@ -1921,6 +1921,20 @@ class AgentManager: "type": "preset", "preset": "claude_code", } + # Suppress Claude Code's bundled plugin skills (/init, /review, + # /security-review, /simplify, /loop, /schedule, /update-config, + # /keybindings-help, /fewer-permission-prompts, /claude-api). + # OpenSwarm has its own skills system that injects skill content + # into the user prompt via _resolve_attached_skills, bypassing the + # SDK's Skill tool entirely — so the bundled skills only cause + # confusion: half mutate ~/.claude state OpenSwarm doesn't use + # (settings.json, keybindings.json), and the rest tell the model + # it can invoke slash commands the backend doesn't intercept. + # Empty list is the SDK's documented "skills off" signal — see + # the `skills` field on ClaudeAgentOptions in claude_agent_sdk + # types.py. User-attached skills are unaffected because they + # don't go through the Skill tool. + options_kwargs["skills"] = [] # exclude_dynamic_sections=True tells the CLI to keep # per-user/per-machine grounding (cwd, git status, recent # commits, OS info) out of the cached system prompt prefix diff --git a/backend/tests/test_agent_manager_unit.py b/backend/tests/test_agent_manager_unit.py index 241a23e8..0c0a702b 100644 --- a/backend/tests/test_agent_manager_unit.py +++ b/backend/tests/test_agent_manager_unit.py @@ -416,6 +416,26 @@ def test_compose_system_prompt_all_none_returns_none(): assert AgentManager()._compose_system_prompt(None, None, None) is None +def test_run_agent_loop_disables_bundled_claude_code_skills(): + """Regression guard for `options_kwargs["skills"] = []` in _run_agent_loop. + + The claude-agent-sdk ships a Skill tool that surfaces Claude Code's + bundled plugin skills (/init, /review, /security-review, /simplify, + /loop, /schedule, /update-config, /keybindings-help, + /fewer-permission-prompts, /claude-api). These are inappropriate in + OpenSwarm — half mutate ~/.claude config the backend doesn't read, and + the rest reference slash commands the backend never intercepts. The + SDK's documented "skills off" signal is `skills=[]` on + ClaudeAgentOptions; user-attached skills bypass the Skill tool and + are unaffected. If this assignment ever gets dropped during a rebase + or refactor the bundled skills come back, so we pin it here. + """ + import inspect + + src = inspect.getsource(AgentManager._run_agent_loop) + assert 'options_kwargs["skills"] = []' in src + + def test_resolve_context_paths_empty_returns_empty(): assert AgentManager()._resolve_context_paths(None) == "" assert AgentManager()._resolve_context_paths([]) == ""