Skip to content

Commit 082f15a

Browse files
tommaso-moroBagToadCopilot
authored
Add support for installation in multiple agent hosts in gh skills install (cli#13209)
* add support for installation in multiple agent host * print correct dir in warning * remove dir as it depends on user vs project installation scope * Move comment closer to assertion in registry test Move the explanatory comment from above the map initialization to directly above the assertions it describes, per review feedback. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * List supported agent names and IDs in help text Replace the self-referencing "run --help" sentence with an inline list of all supported --agent values showing Name (id) pairs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Use heredoc.Docf for Kiro CLI post-install hint Replace individual fmt.Fprintln calls with a single heredoc.Docf block for the Kiro CLI post-install guidance, per review feedback. Also shorten the --agent flag usage line by overriding the auto-generated enum list with a reference to the supported values in the help text. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Kynan Ware <47394200+BagToad@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 998b621 commit 082f15a

5 files changed

Lines changed: 434 additions & 21 deletions

File tree

internal/skills/registry/registry.go

Lines changed: 255 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,16 @@ const (
3434
)
3535

3636
// Agents contains all known agent hosts.
37+
//
38+
// The slice is ordered so that the most widely used agents appear first,
39+
// followed by the rest in alphabetical order. This order is used for
40+
// interactive selection, help output, and flag enum suggestions.
41+
//
42+
// Agents sharing a ProjectDir (such as the shared .agents/skills directory)
43+
// install skills to the same project-scope location, so selecting multiple
44+
// such agents writes each skill only once.
3745
var Agents = []AgentHost{
46+
// Popular agents, listed first for discoverability.
3847
{
3948
ID: "github-copilot",
4049
Name: "GitHub Copilot",
@@ -60,7 +69,7 @@ var Agents = []AgentHost{
6069
UserDir: ".codex/skills",
6170
},
6271
{
63-
ID: "gemini",
72+
ID: "gemini-cli",
6473
Name: "Gemini CLI",
6574
ProjectDir: sharedProjectSkillsDir,
6675
UserDir: ".gemini/skills",
@@ -71,6 +80,242 @@ var Agents = []AgentHost{
7180
ProjectDir: sharedProjectSkillsDir,
7281
UserDir: ".gemini/antigravity/skills",
7382
},
83+
84+
// All other supported agents, alphabetical by ID.
85+
{
86+
ID: "adal",
87+
Name: "AdaL",
88+
ProjectDir: ".adal/skills",
89+
UserDir: ".adal/skills",
90+
},
91+
{
92+
ID: "amp",
93+
Name: "Amp",
94+
ProjectDir: sharedProjectSkillsDir,
95+
UserDir: ".config/agents/skills",
96+
},
97+
{
98+
ID: "augment",
99+
Name: "Augment",
100+
ProjectDir: ".augment/skills",
101+
UserDir: ".augment/skills",
102+
},
103+
{
104+
ID: "bob",
105+
Name: "IBM Bob",
106+
ProjectDir: ".bob/skills",
107+
UserDir: ".bob/skills",
108+
},
109+
{
110+
ID: "cline",
111+
Name: "Cline",
112+
ProjectDir: sharedProjectSkillsDir,
113+
UserDir: ".agents/skills",
114+
},
115+
{
116+
ID: "codebuddy",
117+
Name: "CodeBuddy",
118+
ProjectDir: ".codebuddy/skills",
119+
UserDir: ".codebuddy/skills",
120+
},
121+
{
122+
ID: "command-code",
123+
Name: "Command Code",
124+
ProjectDir: ".commandcode/skills",
125+
UserDir: ".commandcode/skills",
126+
},
127+
{
128+
ID: "continue",
129+
Name: "Continue",
130+
ProjectDir: ".continue/skills",
131+
UserDir: ".continue/skills",
132+
},
133+
{
134+
ID: "cortex",
135+
Name: "Cortex Code",
136+
ProjectDir: ".cortex/skills",
137+
UserDir: ".snowflake/cortex/skills",
138+
},
139+
{
140+
ID: "crush",
141+
Name: "Crush",
142+
ProjectDir: ".crush/skills",
143+
UserDir: ".config/crush/skills",
144+
},
145+
{
146+
ID: "deepagents",
147+
Name: "Deep Agents",
148+
ProjectDir: sharedProjectSkillsDir,
149+
UserDir: ".deepagents/agent/skills",
150+
},
151+
{
152+
ID: "droid",
153+
Name: "Droid",
154+
ProjectDir: ".factory/skills",
155+
UserDir: ".factory/skills",
156+
},
157+
{
158+
ID: "firebender",
159+
Name: "Firebender",
160+
ProjectDir: sharedProjectSkillsDir,
161+
UserDir: ".firebender/skills",
162+
},
163+
{
164+
ID: "goose",
165+
Name: "Goose",
166+
ProjectDir: ".goose/skills",
167+
UserDir: ".config/goose/skills",
168+
},
169+
{
170+
ID: "iflow-cli",
171+
Name: "iFlow CLI",
172+
ProjectDir: ".iflow/skills",
173+
UserDir: ".iflow/skills",
174+
},
175+
{
176+
ID: "junie",
177+
Name: "Junie",
178+
ProjectDir: ".junie/skills",
179+
UserDir: ".junie/skills",
180+
},
181+
{
182+
ID: "kilo",
183+
Name: "Kilo Code",
184+
ProjectDir: ".kilocode/skills",
185+
UserDir: ".kilocode/skills",
186+
},
187+
{
188+
ID: "kimi-cli",
189+
Name: "Kimi Code CLI",
190+
ProjectDir: sharedProjectSkillsDir,
191+
UserDir: ".config/agents/skills",
192+
},
193+
{
194+
ID: "kiro-cli",
195+
Name: "Kiro CLI",
196+
ProjectDir: ".kiro/skills",
197+
UserDir: ".kiro/skills",
198+
},
199+
{
200+
ID: "kode",
201+
Name: "Kode",
202+
ProjectDir: ".kode/skills",
203+
UserDir: ".kode/skills",
204+
},
205+
{
206+
ID: "mcpjam",
207+
Name: "MCPJam",
208+
ProjectDir: ".mcpjam/skills",
209+
UserDir: ".mcpjam/skills",
210+
},
211+
{
212+
ID: "mistral-vibe",
213+
Name: "Mistral Vibe",
214+
ProjectDir: ".vibe/skills",
215+
UserDir: ".vibe/skills",
216+
},
217+
{
218+
ID: "mux",
219+
Name: "Mux",
220+
ProjectDir: ".mux/skills",
221+
UserDir: ".mux/skills",
222+
},
223+
{
224+
ID: "neovate",
225+
Name: "Neovate",
226+
ProjectDir: ".neovate/skills",
227+
UserDir: ".neovate/skills",
228+
},
229+
{
230+
ID: "openclaw",
231+
Name: "OpenClaw",
232+
ProjectDir: "skills",
233+
UserDir: ".openclaw/skills",
234+
},
235+
{
236+
ID: "opencode",
237+
Name: "OpenCode",
238+
ProjectDir: sharedProjectSkillsDir,
239+
UserDir: ".config/opencode/skills",
240+
},
241+
{
242+
ID: "openhands",
243+
Name: "OpenHands",
244+
ProjectDir: ".openhands/skills",
245+
UserDir: ".openhands/skills",
246+
},
247+
{
248+
ID: "pi",
249+
Name: "Pi",
250+
ProjectDir: ".pi/skills",
251+
UserDir: ".pi/agent/skills",
252+
},
253+
{
254+
ID: "pochi",
255+
Name: "Pochi",
256+
ProjectDir: ".pochi/skills",
257+
UserDir: ".pochi/skills",
258+
},
259+
{
260+
ID: "qoder",
261+
Name: "Qoder",
262+
ProjectDir: ".qoder/skills",
263+
UserDir: ".qoder/skills",
264+
},
265+
{
266+
ID: "qwen-code",
267+
Name: "Qwen Code",
268+
ProjectDir: ".qwen/skills",
269+
UserDir: ".qwen/skills",
270+
},
271+
{
272+
ID: "replit",
273+
Name: "Replit",
274+
ProjectDir: sharedProjectSkillsDir,
275+
UserDir: ".config/agents/skills",
276+
},
277+
{
278+
ID: "roo",
279+
Name: "Roo Code",
280+
ProjectDir: ".roo/skills",
281+
UserDir: ".roo/skills",
282+
},
283+
{
284+
ID: "trae",
285+
Name: "Trae",
286+
ProjectDir: ".trae/skills",
287+
UserDir: ".trae/skills",
288+
},
289+
{
290+
ID: "trae-cn",
291+
Name: "Trae CN",
292+
ProjectDir: ".trae/skills",
293+
UserDir: ".trae-cn/skills",
294+
},
295+
{
296+
ID: "universal",
297+
Name: "Universal",
298+
ProjectDir: sharedProjectSkillsDir,
299+
UserDir: ".config/agents/skills",
300+
},
301+
{
302+
ID: "warp",
303+
Name: "Warp",
304+
ProjectDir: sharedProjectSkillsDir,
305+
UserDir: ".agents/skills",
306+
},
307+
{
308+
ID: "windsurf",
309+
Name: "Windsurf",
310+
ProjectDir: ".windsurf/skills",
311+
UserDir: ".codeium/windsurf/skills",
312+
},
313+
{
314+
ID: "zencoder",
315+
Name: "Zencoder",
316+
ProjectDir: ".zencoder/skills",
317+
UserDir: ".zencoder/skills",
318+
},
74319
}
75320

76321
// FindByID returns the agent host with the given ID, or an error if not found.
@@ -97,6 +342,15 @@ func AgentIDs() []string {
97342
return ids
98343
}
99344

345+
// AgentHelpList returns a newline-separated bulleted list of agents for help text.
346+
func AgentHelpList() string {
347+
lines := make([]string, len(Agents))
348+
for i, h := range Agents {
349+
lines[i] = fmt.Sprintf(" - %s (%s)", h.Name, h.ID)
350+
}
351+
return strings.Join(lines, "\n")
352+
}
353+
100354
// AgentNames returns the display names of all agents for prompting.
101355
func AgentNames() []string {
102356
names := make([]string, len(Agents))

internal/skills/registry/registry_test.go

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ func TestFindByID(t *testing.T) {
1919
{name: "claude-code", id: "claude-code", wantName: "Claude Code"},
2020
{name: "cursor", id: "cursor", wantName: "Cursor"},
2121
{name: "codex", id: "codex", wantName: "Codex"},
22-
{name: "gemini", id: "gemini", wantName: "Gemini CLI"},
22+
{name: "gemini-cli", id: "gemini-cli", wantName: "Gemini CLI"},
2323
{name: "antigravity", id: "antigravity", wantName: "Antigravity"},
2424
{name: "unknown agent", id: "nonexistent", wantErr: "unknown agent"},
2525
}
@@ -89,7 +89,7 @@ func TestInstallDir(t *testing.T) {
8989
},
9090
{
9191
name: "gemini project scope",
92-
hostID: "gemini",
92+
hostID: "gemini-cli",
9393
scope: ScopeProject,
9494
gitRoot: "/tmp/monalisa-repo",
9595
homeDir: "/home/monalisa",
@@ -167,7 +167,18 @@ func TestRepoNameFromRemote(t *testing.T) {
167167

168168
func TestUniqueProjectDirs(t *testing.T) {
169169
dirs := UniqueProjectDirs()
170-
assert.Equal(t, []string{".agents/skills", ".claude/skills"}, dirs)
170+
seen := map[string]int{}
171+
for _, d := range dirs {
172+
seen[d]++
173+
}
174+
// The shared .agents/skills dir and .claude/skills must both be present
175+
// and listed exactly once each.
176+
assert.Equal(t, 1, seen[".agents/skills"], "expected .agents/skills exactly once")
177+
assert.Equal(t, 1, seen[".claude/skills"], "expected .claude/skills exactly once")
178+
// No project dir should appear more than once.
179+
for d, n := range seen {
180+
assert.LessOrEqualf(t, n, 1, "project dir %q appears %d times", d, n)
181+
}
171182
}
172183

173184
func TestScopeLabels(t *testing.T) {

0 commit comments

Comments
 (0)