@@ -34,12 +34,15 @@ func init() {
3434 rootCmd .AddCommand (initCmd )
3535}
3636
37- func initializeProject (cmd * cobra.Command ) error { //nolint:funlen
37+ func initializeProject (cmd * cobra.Command ) error { //nolint:funlen,gocyclo,cyclop
3838 overwrite , _ := cmd .Flags ().GetBool ("overwrite" )
3939 userspace , _ := cmd .Flags ().GetBool ("userspace" )
4040 skipMigrations , _ := cmd .Flags ().GetBool ("skip-migrations" )
4141
42- var configPath , gitignorePath , scmShortcutsPath , gitShortcutsPath , mcpShortcutsPath , shellsShortcutsPath , exportShortcutsPath , a2aShortcutsPath , mcpPath , keybindingsPath , promptsPath , channelsPath , heartbeatPath , computerUsePath , agentsPath string
42+ var configPath , gitignorePath , scmShortcutsPath , gitShortcutsPath ,
43+ mcpShortcutsPath , shellsShortcutsPath , exportShortcutsPath ,
44+ a2aShortcutsPath , skillsShortcutsPath , mcpPath , keybindingsPath , promptsPath ,
45+ channelsPath , heartbeatPath , computerUsePath , agentsPath , skillsDirPath string
4346
4447 if userspace {
4548 homeDir , err := os .UserHomeDir ()
@@ -54,13 +57,15 @@ func initializeProject(cmd *cobra.Command) error { //nolint:funlen
5457 shellsShortcutsPath = filepath .Join (homeDir , config .ConfigDirName , "shortcuts" , "shells.yaml" )
5558 exportShortcutsPath = filepath .Join (homeDir , config .ConfigDirName , "shortcuts" , "export.yaml" )
5659 a2aShortcutsPath = filepath .Join (homeDir , config .ConfigDirName , "shortcuts" , "a2a.yaml" )
60+ skillsShortcutsPath = filepath .Join (homeDir , config .ConfigDirName , "shortcuts" , "skills.yaml" )
5761 mcpPath = filepath .Join (homeDir , config .ConfigDirName , config .MCPFileName )
5862 keybindingsPath = filepath .Join (homeDir , config .ConfigDirName , config .KeybindingsFileName )
5963 promptsPath = filepath .Join (homeDir , config .ConfigDirName , config .PromptsFileName )
6064 channelsPath = filepath .Join (homeDir , config .ConfigDirName , config .ChannelsFileName )
6165 heartbeatPath = filepath .Join (homeDir , config .ConfigDirName , config .HeartbeatFileName )
6266 computerUsePath = filepath .Join (homeDir , config .ConfigDirName , config .ComputerUseFileName )
6367 agentsPath = filepath .Join (homeDir , config .ConfigDirName , config .AgentsFileName )
68+ skillsDirPath = filepath .Join (homeDir , config .ConfigDirName , "skills" )
6469 } else {
6570 configPath = config .DefaultConfigPath
6671 gitignorePath = filepath .Join (config .ConfigDirName , config .GitignoreFileName )
@@ -70,17 +75,19 @@ func initializeProject(cmd *cobra.Command) error { //nolint:funlen
7075 shellsShortcutsPath = filepath .Join (config .ConfigDirName , "shortcuts" , "shells.yaml" )
7176 exportShortcutsPath = filepath .Join (config .ConfigDirName , "shortcuts" , "export.yaml" )
7277 a2aShortcutsPath = filepath .Join (config .ConfigDirName , "shortcuts" , "a2a.yaml" )
78+ skillsShortcutsPath = filepath .Join (config .ConfigDirName , "shortcuts" , "skills.yaml" )
7379 mcpPath = filepath .Join (config .ConfigDirName , config .MCPFileName )
7480 keybindingsPath = config .DefaultKeybindingsPath
7581 promptsPath = config .DefaultPromptsPath
7682 channelsPath = config .DefaultChannelsPath
7783 heartbeatPath = config .DefaultHeartbeatPath
7884 computerUsePath = config .DefaultComputerUsePath
7985 agentsPath = config .DefaultAgentsPath
86+ skillsDirPath = filepath .Join (config .ConfigDirName , "skills" )
8087 }
8188
8289 if ! overwrite {
83- if err := validateFilesNotExist (configPath , gitignorePath , scmShortcutsPath , gitShortcutsPath , mcpShortcutsPath , shellsShortcutsPath , exportShortcutsPath , a2aShortcutsPath , mcpPath , keybindingsPath , promptsPath , channelsPath , heartbeatPath , computerUsePath , agentsPath ); err != nil {
90+ if err := validateFilesNotExist (configPath , gitignorePath , scmShortcutsPath , gitShortcutsPath , mcpShortcutsPath , shellsShortcutsPath , exportShortcutsPath , a2aShortcutsPath , skillsShortcutsPath , mcpPath , keybindingsPath , promptsPath , channelsPath , heartbeatPath , computerUsePath , agentsPath ); err != nil {
8491 return err
8592 }
8693 }
@@ -128,6 +135,10 @@ plans/
128135 return fmt .Errorf ("failed to create A2A shortcuts file: %w" , err )
129136 }
130137
138+ if err := createSkillsShortcutsFile (skillsShortcutsPath ); err != nil {
139+ return fmt .Errorf ("failed to create Skills shortcuts file: %w" , err )
140+ }
141+
131142 if err := createMCPConfigFile (mcpPath ); err != nil {
132143 return fmt .Errorf ("failed to create MCP config file: %w" , err )
133144 }
@@ -158,6 +169,10 @@ plans/
158169 return fmt .Errorf ("failed to create agents config file: %w" , err )
159170 }
160171
172+ if err := createSkillsDir (skillsDirPath ); err != nil {
173+ return fmt .Errorf ("failed to create skills directory: %w" , err )
174+ }
175+
161176 var scopeDesc string
162177 if userspace {
163178 scopeDesc = "userspace"
@@ -174,13 +189,15 @@ plans/
174189 fmt .Printf (" Created: %s\n " , shellsShortcutsPath )
175190 fmt .Printf (" Created: %s\n " , exportShortcutsPath )
176191 fmt .Printf (" Created: %s\n " , a2aShortcutsPath )
192+ fmt .Printf (" Created: %s\n " , skillsShortcutsPath )
177193 fmt .Printf (" Created: %s\n " , mcpPath )
178194 fmt .Printf (" Created: %s\n " , keybindingsPath )
179195 fmt .Printf (" Created: %s\n " , promptsPath )
180196 fmt .Printf (" Created: %s\n " , channelsPath )
181197 fmt .Printf (" Created: %s\n " , heartbeatPath )
182198 fmt .Printf (" Created: %s\n " , computerUsePath )
183199 fmt .Printf (" Created: %s\n " , agentsPath )
200+ fmt .Printf (" Created: %s/\n " , skillsDirPath )
184201 if migrated {
185202 fmt .Printf ("\n %s Migrated legacy `channels:` block from config.yaml into %s.\n " , icons .CheckMarkStyle .Render (icons .CheckMark ), channelsPath )
186203 fmt .Printf (" You can now remove the `channels:` block from %s.\n " , configPath )
@@ -517,6 +534,15 @@ func createAgentsConfigFile(path string) error {
517534 return config .SaveAgents (path , config .DefaultAgentsConfig ())
518535}
519536
537+ // createSkillsDir creates an empty skills directory. Skills are authored by
538+ // dropping a folder containing SKILL.md into this directory; see docs/skills.md for the format.
539+ func createSkillsDir (dir string ) error {
540+ if err := os .MkdirAll (dir , 0755 ); err != nil {
541+ return fmt .Errorf ("failed to create skills directory: %w" , err )
542+ }
543+ return nil
544+ }
545+
520546// createMCPConfigFile creates the MCP configuration YAML file
521547func createMCPConfigFile (path string ) error {
522548 if err := os .MkdirAll (filepath .Dir (path ), 0755 ); err != nil {
@@ -667,6 +693,39 @@ shortcuts:
667693 return os .WriteFile (path , []byte (a2aShortcutsContent ), 0644 )
668694}
669695
696+ // createSkillsShortcutsFile creates the Agent Skills shortcuts YAML file
697+ func createSkillsShortcutsFile (path string ) error {
698+ if err := os .MkdirAll (filepath .Dir (path ), 0755 ); err != nil {
699+ return fmt .Errorf ("failed to create shortcuts directory: %w" , err )
700+ }
701+
702+ skillsShortcutsContent := `---
703+ # Agent Skills Shortcuts
704+ # Manage Agent Skills from within chat
705+ #
706+ # Usage:
707+ # - /skills list - List discovered skills
708+ # - /skills install <github-url> - Install a skill from a public GitHub repo
709+ # - /skills uninstall <name> - Uninstall a skill by name
710+
711+ shortcuts:
712+ - name: skills
713+ description: "Manage Agent Skills"
714+ command: infer
715+ args:
716+ - skills
717+ subcommands:
718+ - name: list
719+ description: "List discovered skills"
720+ - name: install
721+ description: "Install a skill from a public GitHub repo (usage: <github-url> [--user] [--overwrite])"
722+ - name: uninstall
723+ description: "Uninstall a skill by name (usage: <name> [--user])"
724+ `
725+
726+ return os .WriteFile (path , []byte (skillsShortcutsContent ), 0644 )
727+ }
728+
670729// handleMigrations handles the migration logic for the init command
671730func handleMigrations () {
672731 defaultConfig := config .DefaultConfig ()
0 commit comments