Skip to content

Commit 36019eb

Browse files
authored
feat: Auto-register ai-skills for extensions whenever applicable (#1840)
* feat: Auto-register ai-skills for extensions whenever applicable * fix: failing test * fix: address copilot review comments – path traversal guard and use short_name in title * fix: address remaining copilot review comments – is_file guard, skills type-validation, and exact extension ownership check on fallback rmtree * fix: address copilot round-3 comments – align skill naming with presets.py convention, safe rmdir on fail, require SKILL.md for fallback rmtree, normalize skill_count in CLI * fix: is_dir() guard in fast-path rmtree and fix ghost-skill assertion naming * fix: path-traversal guard on skill_name in both rmtree paths of _unregister_extension_skills * fix: add SKILL.md ownership check to fast-path rmtree and alias shadowed _get_skills_dir import
1 parent fb152eb commit 36019eb

File tree

6 files changed

+972
-5
lines changed

6 files changed

+972
-5
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ The `specify` command supports the following options:
292292
| `--skip-tls` | Flag | Skip SSL/TLS verification (not recommended) |
293293
| `--debug` | Flag | Enable detailed debug output for troubleshooting |
294294
| `--github-token` | Option | GitHub token for API requests (or set GH_TOKEN/GITHUB_TOKEN env variable) |
295-
| `--ai-skills` | Flag | Install Prompt.MD templates as agent skills in agent-specific `skills/` directory (requires `--ai`) |
295+
| `--ai-skills` | Flag | Install Prompt.MD templates as agent skills in agent-specific `skills/` directory (requires `--ai`). Extension commands are also auto-registered as skills when extensions are added later. |
296296
| `--branch-numbering` | Option | Branch numbering strategy: `sequential` (default — `001`, `002`, `003`) or `timestamp` (`YYYYMMDD-HHMMSS`). Timestamp mode is useful for distributed teams to avoid numbering conflicts |
297297

298298
### Examples

extensions/EXTENSION-USER-GUIDE.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,21 @@ Provided commands:
187187
Check: .specify/extensions/jira/
188188
```
189189

190+
### Automatic Agent Skill Registration
191+
192+
If your project was initialized with `--ai-skills`, extension commands are **automatically registered as agent skills** during installation. This ensures that extensions are discoverable by agents that use the [agentskills.io](https://agentskills.io) skill specification.
193+
194+
```text
195+
✓ Extension installed successfully!
196+
197+
Jira Integration (v1.0.0)
198+
...
199+
200+
✓ 3 agent skill(s) auto-registered
201+
```
202+
203+
When an extension is removed, its corresponding skills are also cleaned up automatically. Pre-existing skills that were manually customized are never overwritten.
204+
190205
---
191206

192207
## Using Extensions

src/specify_cli/__init__.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3594,6 +3594,15 @@ def extension_add(
35943594
for cmd in manifest.commands:
35953595
console.print(f" • {cmd['name']} - {cmd.get('description', '')}")
35963596

3597+
# Report agent skills registration
3598+
reg_meta = manager.registry.get(manifest.id)
3599+
reg_skills = reg_meta.get("registered_skills", []) if reg_meta else []
3600+
# Normalize to guard against corrupted registry entries
3601+
if not isinstance(reg_skills, list):
3602+
reg_skills = []
3603+
if reg_skills:
3604+
console.print(f"\n[green]✓[/green] {len(reg_skills)} agent skill(s) auto-registered")
3605+
35973606
console.print("\n[yellow]⚠[/yellow] Configuration may be required")
35983607
console.print(f" Check: .specify/extensions/{manifest.id}/")
35993608

@@ -3632,14 +3641,19 @@ def extension_remove(
36323641
installed = manager.list_installed()
36333642
extension_id, display_name = _resolve_installed_extension(extension, installed, "remove")
36343643

3635-
# Get extension info for command count
3644+
# Get extension info for command and skill counts
36363645
ext_manifest = manager.get_extension(extension_id)
36373646
cmd_count = len(ext_manifest.commands) if ext_manifest else 0
3647+
reg_meta = manager.registry.get(extension_id)
3648+
raw_skills = reg_meta.get("registered_skills") if reg_meta else None
3649+
skill_count = len(raw_skills) if isinstance(raw_skills, list) else 0
36383650

36393651
# Confirm removal
36403652
if not force:
36413653
console.print("\n[yellow]⚠ This will remove:[/yellow]")
36423654
console.print(f" • {cmd_count} commands from AI agent")
3655+
if skill_count:
3656+
console.print(f" • {skill_count} agent skill(s)")
36433657
console.print(f" • Extension directory: .specify/extensions/{extension_id}/")
36443658
if not keep_config:
36453659
console.print(" • Config files (will be backed up)")

0 commit comments

Comments
 (0)