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
45 changes: 44 additions & 1 deletion .agent/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@ Subagents provide specialized capabilities. Read them when tasks require domain
| `workflows/` | Development processes - branching, releases, PR reviews, quality gates | git-workflow, plans, release, version-bump, pr, review-issue-pr, preflight, postflight, ralph-loop, session-review |
| `templates/` | Document templates - PRDs, task lists, planning documents | prd-template, tasks-template, plans-template, todo-template |
| `workflows/branch/` | Branch conventions - naming, purpose, merge strategies per branch type | feature, bugfix, hotfix, refactor, chore, experiment, release |
| `scripts/commands/` | Slash commands - save-todo, remember, recall, code-simplifier, humanise and other interactive commands | save-todo, remember, recall, code-simplifier, humanise |
| `scripts/commands/` | Slash commands - save-todo, remember, recall, code-simplifier, humanise, add-skill and other interactive commands | save-todo, remember, recall, code-simplifier, humanise, add-skill |

<!-- AI-CONTEXT-END -->

Expand Down Expand Up @@ -554,6 +554,7 @@ aidevops features # List available features
| `aidevops upgrade` | Alias for update |
| `aidevops repos` | List registered projects |
| `aidevops repos add` | Register current project |
| `aidevops skill <cmd>` | Manage imported skills (add/list/check/update/remove/generate) |
| `aidevops detect` | Find unregistered aidevops projects |
| `aidevops update-tools` | Check for outdated tools |
| `aidevops uninstall` | Remove aidevops |
Expand Down Expand Up @@ -600,6 +601,7 @@ For AI-assisted setup guidance, see `aidevops/setup.md`.
| Programmatic video | `tools/video/remotion.md` (React video creation, animations) |
| AI image/video generation | `tools/video/higgsfield.md` (100+ generative models via unified API) |
| Mobile emulators | `tools/mobile/minisim.md` (iOS simulator, Android emulator launcher) |
| Importing skills | `scripts/commands/add-skill.md` (import, naming, update tracking) |

## Security

Expand Down Expand Up @@ -644,6 +646,47 @@ Never create files in `~/` root for files needed only with the current task.
| `full-loop-helper.sh` | End-to-end development loop (task → PR → deploy) |
| `session-review-helper.sh` | Gather session context for completeness review |
| `humanise-update-helper.sh` | Check for upstream updates to humanise subagent |
| `add-skill-helper.sh` | Import external skills from GitHub repos |
| `skill-update-helper.sh` | Check/update imported skills from upstream |
| `generate-skills.sh` | Generate SKILL.md stubs for cross-tool discovery |

## Imported Skills

Import community [Agent Skills](https://agentskills.io) into aidevops with upstream tracking.

**Naming convention**: Imported skills use a `-skill` suffix to distinguish from native subagents:

| Type | Pattern | Example | Managed by |
|------|---------|---------|------------|
| Native subagent | `{name}.md` | `playwright.md` | aidevops team |
| Imported skill | `{name}-skill.md` | `playwright-skill.md` | Upstream repo |

**CLI commands:**

```bash
aidevops skill add <source> # Import from GitHub (→ *-skill.md)
aidevops skill list # List imported skills
aidevops skill check # Check for upstream updates
aidevops skill update [name] # Pull upstream changes
aidevops skill remove <name> # Remove imported skill
aidevops skill generate # Generate SKILL.md stubs for cross-tool discovery
aidevops skill clean # Remove generated SKILL.md stubs
```

**How it works:**
1. Clones the source repo, detects format (SKILL.md, AGENTS.md, .cursorrules)
2. Converts to aidevops subagent format with `-skill.md` suffix
3. Places in appropriate category folder (auto-detected from content)
4. Registers in `.agent/configs/skill-sources.json` for update tracking
5. Telemetry disabled - no data sent to skills.sh or third parties

**When issues arise with a subagent:**
- `*-skill.md` → Check upstream for updates: `aidevops skill check`
- Native `.md` → Evolve locally, submit PR to aidevops

**Cross-tool discovery**: `aidevops skill generate` creates lightweight SKILL.md stubs so other tools (Cursor, VS Code Copilot, OpenCode) can discover aidevops subagents without changing our file structure.

**Related scripts:** `add-skill-helper.sh`, `skill-update-helper.sh`, `generate-skills.sh`

## Quality Workflow

Expand Down
93 changes: 70 additions & 23 deletions .agent/scripts/add-skill-helper.sh
Original file line number Diff line number Diff line change
Expand Up @@ -283,11 +283,14 @@ determine_target_path() {
category="services/hosting"
fi

echo "$category/$skill_name"
# Append -skill suffix to distinguish imported skills from native subagents
# This enables: glob *-skill.md for imports, update checks, conflict avoidance
echo "$category/${skill_name}-skill"
return 0
}

# Check for conflicts with existing files
# Returns conflict info with type: NATIVE (our subagent) or IMPORTED (previous skill)
check_conflicts() {
local target_path="$1"
local agent_dir="$2"
Expand All @@ -299,11 +302,28 @@ check_conflicts() {
local conflicts=()

if [[ -f "$md_path" ]]; then
conflicts+=("$md_path")
if [[ "$md_path" == *-skill.md ]]; then
conflicts+=("IMPORTED: $md_path")
else
conflicts+=("NATIVE: $md_path")
fi
fi

if [[ -d "$dir_path" ]]; then
conflicts+=("$dir_path/")
if [[ "$dir_path" == *-skill ]]; then
conflicts+=("IMPORTED: $dir_path/")
else
conflicts+=("NATIVE: $dir_path/")
fi
fi

# Also check for native subagent without -skill suffix (same base name)
local base_name="${target_path%-skill}"
local native_md="${agent_dir}/${base_name}.md"
if [[ "$target_path" == *-skill && -f "$native_md" ]]; then
# Native subagent exists with same base name - not a conflict since
# -skill suffix differentiates, but inform the user
conflicts+=("INFO: Native subagent exists at $native_md (no conflict, -skill suffix differentiates)")
fi

if [[ ${#conflicts[@]} -gt 0 ]]; then
Expand Down Expand Up @@ -491,8 +511,8 @@ cmd_add() {
local skill_name="${custom_name:-$(basename "${subpath:-$repo}")}"
skill_name=$(to_kebab_case "$skill_name")
# openskills installs to ~/.config/opencode/skills/<name>/SKILL.md
# Register with .md extension for consistency with other paths
register_skill "$skill_name" "https://github.com/$owner/$repo" ".agent/skills/${skill_name}.md" "skill-md" "" "openskills" "Installed via openskills CLI"
# Register with -skill suffix for consistency with direct imports
register_skill "$skill_name" "https://github.com/$owner/$repo" ".agent/skills/${skill_name}-skill.md" "skill-md" "" "openskills" "Installed via openskills CLI"
return 0
fi
log_warning "openskills failed, falling back to direct fetch"
Expand Down Expand Up @@ -558,35 +578,62 @@ cmd_add() {
local conflicts
conflicts=$(check_conflicts "$target_path" ".agent") || true
if [[ -n "$conflicts" ]]; then
if [[ "$force" != true ]]; then
log_warning "Conflicts detected:"
echo "$conflicts" | while read -r conflict; do
echo " - $conflict"
# Filter out INFO lines (informational, not blocking)
local blocking_conflicts
blocking_conflicts=$(echo "$conflicts" | grep -v "^INFO:" || true)
local info_lines
info_lines=$(echo "$conflicts" | grep "^INFO:" || true)

# Show info lines (native subagent coexistence)
if [[ -n "$info_lines" ]]; then
echo "$info_lines" | while read -r info; do
log_info "${info#INFO: }"
done
echo ""
fi

# Handle blocking conflicts
if [[ -n "$blocking_conflicts" && "$force" != true ]]; then
# Determine conflict type for better messaging
if echo "$blocking_conflicts" | grep -q "^NATIVE:"; then
log_warning "Conflicts with native aidevops subagent(s):"
echo "$blocking_conflicts" | while read -r conflict; do
echo " - ${conflict#NATIVE: }"
done
echo ""
echo "The -skill suffix should prevent this. If you see this,"
echo "the imported skill has the same name as a native subagent."
echo ""
elif echo "$blocking_conflicts" | grep -q "^IMPORTED:"; then
log_warning "Conflicts with previously imported skill(s):"
echo "$blocking_conflicts" | while read -r conflict; do
echo " - ${conflict#IMPORTED: }"
done
echo ""
else
log_warning "Conflicts detected:"
echo "$blocking_conflicts" | while read -r conflict; do
echo " - $conflict"
done
echo ""
fi

echo "Options:"
echo " 1. Merge (add new content to existing)"
echo " 2. Replace (overwrite existing)"
echo " 3. Separate (use different name)"
echo " 4. Skip (cancel import)"
echo " 1. Replace (overwrite existing)"
echo " 2. Separate (use different name)"
echo " 3. Skip (cancel import)"
echo ""
read -rp "Choose option [1-4]: " choice
read -rp "Choose option [1-3]: " choice

case "$choice" in
1)
log_info "Merging with existing..."
# TODO: Implement merge logic
log_warning "Merge not yet implemented, using replace"
;;
2)
log_info "Replacing existing..."
;;
3)
2)
read -rp "Enter new name: " new_name
skill_name=$(to_kebab_case "$new_name")
target_path=$(determine_target_path "$skill_name" "$description" "$source_dir")
;;
Comment on lines 632 to 635
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Recompute target_path using the resolved skill directory.
When the user chooses “Separate”, you pass $source_dir into determine_target_path, which can point at the repo root and miss SKILL.md for nested skills. That can miscategorize the import. Use $skill_source_dir instead.

🐛 Proposed fix
-                    target_path=$(determine_target_path "$skill_name" "$description" "$source_dir")
+                    target_path=$(determine_target_path "$skill_name" "$description" "$skill_source_dir")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
read -rp "Enter new name: " new_name
skill_name=$(to_kebab_case "$new_name")
target_path=$(determine_target_path "$skill_name" "$description" "$source_dir")
;;
read -rp "Enter new name: " new_name
skill_name=$(to_kebab_case "$new_name")
target_path=$(determine_target_path "$skill_name" "$description" "$skill_source_dir")
;;
🤖 Prompt for AI Agents
In @.agent/scripts/add-skill-helper.sh around lines 632 - 635, The call to
determine_target_path is using the generic source_dir which can be the repo root
and miss nested SKILL.md files; update the "Separate" branch so after reading
new_name and computing skill_name it calls determine_target_path with
skill_source_dir (not source_dir) so the resolved skill directory is used when
categorizing/importing the skill (ensure variables referenced are skill_name,
new_name, determine_target_path, and skill_source_dir).

4|*)
3|*)
log_info "Import cancelled"
return 0
;;
Expand Down Expand Up @@ -738,7 +785,7 @@ cmd_check_updates() {
# Get latest commit from GitHub API
local api_url="https://api.github.com/repos/$owner/$repo/commits?per_page=1"
local latest_commit
latest_commit=$(curl -s "$api_url" | jq -r '.[0].sha // empty' 2>/dev/null)
latest_commit=$(curl -s --connect-timeout 10 --max-time 30 "$api_url" | jq -r '.[0].sha // empty' 2>/dev/null)

if [[ -z "$latest_commit" ]]; then
log_warning "Could not fetch latest commit for $name"
Expand Down
22 changes: 20 additions & 2 deletions .agent/scripts/commands/add-skill.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,17 @@ URL/Repo: $ARGUMENTS
## Quick Reference

```bash
# Import skill from GitHub
# Import skill from GitHub (saved as *-skill.md)
/add-skill dmmulroy/cloudflare-skill
# → .agent/services/hosting/cloudflare-skill.md

# Import specific skill from multi-skill repo
/add-skill anthropics/skills/pdf
# → .agent/tools/pdf-skill.md

# Import with custom name
/add-skill vercel-labs/agent-skills --name vercel-deploy
# → .agent/tools/deployment/vercel-deploy-skill.md

# List imported skills
/add-skill list
Expand All @@ -27,6 +30,21 @@ URL/Repo: $ARGUMENTS
/add-skill check-updates
```

## Naming Convention

Imported skills are saved with a `-skill` suffix to distinguish them from native aidevops subagents:

| Type | Example | Managed by |
|------|---------|------------|
| Native subagent | `playwright.md` | aidevops team, evolves with framework |
| Imported skill | `playwright-skill.md` | Upstream repo, checked for updates |

This means:
- No name clashes between imports and native subagents
- `*-skill.md` glob finds all imports instantly
- `aidevops skill check` knows which files to check for upstream updates
- Issues with imported skills → check upstream; issues with native → evolve locally

## Workflow

### Step 1: Parse Input
Expand Down Expand Up @@ -111,7 +129,7 @@ Imported skills are tracked in `.agent/configs/skill-sources.json`:
"name": "cloudflare",
"upstream_url": "https://github.com/dmmulroy/cloudflare-skill",
"upstream_commit": "abc123...",
"local_path": ".agent/services/hosting/cloudflare.md",
"local_path": ".agent/services/hosting/cloudflare-skill.md",
"format_detected": "skill-md",
"imported_at": "2026-01-21T00:00:00Z",
"last_checked": "2026-01-21T00:00:00Z",
Expand Down
29 changes: 25 additions & 4 deletions .agent/tools/browser/playwriter.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,14 @@ Add to your MCP client configuration:
"mcp": {
"playwriter": {
"type": "local",
"command": ["npx", "playwriter@latest"],
"command": ["/opt/homebrew/bin/npx", "-y", "playwriter@latest"],
"enabled": true
}
}
}
```text
```

> **Note**: Use full path to `npx` (e.g., `/opt/homebrew/bin/npx` on macOS with Homebrew) for reliability. The `-y` flag auto-confirms package installation.

**Claude Desktop** (`claude_desktop_config.json`):

Expand All @@ -73,11 +75,30 @@ Add to your MCP client configuration:
"mcpServers": {
"playwriter": {
"command": "npx",
"args": ["playwriter@latest"]
"args": ["-y", "playwriter@latest"]
}
}
}
```text
```

**Enable per-agent** (OpenCode tools section):

```json
{
"tools": {
"playwriter_*": false
},
"agent": {
"Build+": {
"tools": {
"playwriter_*": true
}
}
}
}
```

> **Tip**: Disable globally with `"playwriter_*": false` in `tools`, then enable per-agent to reduce context token usage.

## Usage

Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- add `aidevops skill` CLI command for managing agent skills with telemetry disabled (#154)
- add `-skill` suffix convention for imported skills to distinguish from native subagents
- add `generate`/`clean` subcommands for SKILL.md cross-tool discovery stubs

## [2.72.0] - 2026-01-22

### Added

- add MiniSim iOS/Android emulator launcher support (#151)

## [2.71.0] - 2026-01-22

### Added
Expand Down
Loading
Loading