Skip to content

Commit b66425e

Browse files
authored
Add Claude Code skill and install command (#43)
## Summary - Adds `cmd/skills/cloudamqp-cli/` — a Claude Code skill that teaches Claude how to use the `cloudamqp` CLI (commands, auth, async behavior, reference guides for scripting, upgrades, and VPC setup) - Adds `cmd/install.go` — implements `cloudamqp install skills` which embeds the skill files in the binary and copies them to `~/.claude/skills/cloudamqp-cli/` - Updates `README.md` with a short Claude Code section Mirrors the pattern from [microsoft/playwright-cli](https://github.com/microsoft/playwright-cli). ## Test plan - [x] `cloudamqp install skills` creates `~/.claude/skills/cloudamqp-cli/` with `SKILL.md` and `references/` - [x] Skill appears in Claude Code skill list after install - [x] `go build` succeeds with embedded skill files
2 parents 5935e4b + fb35cbb commit b66425e

7 files changed

Lines changed: 476 additions & 0 deletions

File tree

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,16 @@ A command line interface for the CloudAMQP API that provides complete management
1212
- **User-Friendly**: Clear help messages, examples, and safety confirmations
1313
- **Error Handling**: Proper API error extraction and display
1414

15+
## Claude Code
16+
17+
Install skills to let Claude Code manage CloudAMQP instances on your behalf:
18+
19+
```bash
20+
cloudamqp install skills
21+
```
22+
23+
This copies skills to `~/.claude/skills/cloudamqp-cli/`. Claude Code discovers them automatically.
24+
1525
## Installation
1626

1727
### Pre-built binaries

cmd/install.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package cmd
2+
3+
import (
4+
"embed"
5+
"fmt"
6+
"io/fs"
7+
"os"
8+
"path/filepath"
9+
"strings"
10+
11+
"github.com/spf13/cobra"
12+
)
13+
14+
//go:embed all:skills
15+
var skillsFS embed.FS
16+
17+
var installCmd = &cobra.Command{
18+
Use: "install",
19+
Short: "Install integrations",
20+
}
21+
22+
var installSkillsCmd = &cobra.Command{
23+
Use: "skills",
24+
Short: "Install Claude Code skills to ~/.claude/skills/",
25+
Args: cobra.NoArgs,
26+
Long: `Install the CloudAMQP CLI skills for Claude Code.
27+
28+
Skills teach Claude how to use the cloudamqp CLI. After installation,
29+
Claude Code will automatically discover and use them.
30+
31+
Skills are installed to: ~/.claude/skills/cloudamqp-cli/`,
32+
RunE: func(cmd *cobra.Command, args []string) error {
33+
home, err := os.UserHomeDir()
34+
if err != nil {
35+
return fmt.Errorf("could not determine home directory: %w", err)
36+
}
37+
dest := filepath.Join(home, ".claude", "skills", "cloudamqp-cli")
38+
39+
const embedPrefix = "skills/cloudamqp-cli"
40+
err = fs.WalkDir(skillsFS, embedPrefix, func(path string, d fs.DirEntry, err error) error {
41+
if err != nil {
42+
return err
43+
}
44+
// Embedded paths always use forward slashes. Use strings.TrimPrefix
45+
// then filepath.FromSlash so this works correctly on Windows too.
46+
rel := strings.TrimPrefix(strings.TrimPrefix(path, embedPrefix), "/")
47+
target := filepath.Join(dest, filepath.FromSlash(rel))
48+
if d.IsDir() {
49+
return os.MkdirAll(target, 0755)
50+
}
51+
data, err := skillsFS.ReadFile(path)
52+
if err != nil {
53+
return err
54+
}
55+
return os.WriteFile(target, data, 0644)
56+
})
57+
if err != nil {
58+
return fmt.Errorf("failed to install skills: %w", err)
59+
}
60+
fmt.Printf("Skills installed to %s\n", dest)
61+
return nil
62+
},
63+
}
64+
65+
func init() {
66+
installCmd.AddCommand(installSkillsCmd)
67+
rootCmd.AddCommand(installCmd)
68+
}

cmd/install_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package cmd
2+
3+
import (
4+
"path/filepath"
5+
"testing"
6+
7+
"github.com/stretchr/testify/assert"
8+
"github.com/stretchr/testify/require"
9+
)
10+
11+
func TestInstallSkillsCmd(t *testing.T) {
12+
home := t.TempDir()
13+
t.Setenv("HOME", home)
14+
15+
err := installSkillsCmd.RunE(installSkillsCmd, []string{})
16+
require.NoError(t, err)
17+
18+
base := filepath.Join(home, ".claude", "skills", "cloudamqp-cli")
19+
assert.FileExists(t, filepath.Join(base, "SKILL.md"))
20+
assert.FileExists(t, filepath.Join(base, "references", "scripting.md"))
21+
assert.FileExists(t, filepath.Join(base, "references", "upgrades.md"))
22+
assert.FileExists(t, filepath.Join(base, "references", "vpc-setup.md"))
23+
}
24+
25+
func TestInstallSkillsCmd_NoArgs(t *testing.T) {
26+
err := installSkillsCmd.Args(installSkillsCmd, []string{"unexpected"})
27+
assert.Error(t, err)
28+
}

cmd/skills/cloudamqp-cli/SKILL.md

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
---
2+
name: cloudamqp-cli
3+
description: Manage CloudAMQP instances, VPCs, teams, and RabbitMQ/LavinMQ configuration using the cloudamqp CLI. Use this skill whenever the user wants to create, list, inspect, update, delete, upgrade, restart, or troubleshoot CloudAMQP instances — even if they just say "spin up a RabbitMQ", "check my instances", or "upgrade my broker". Also use it for VPC setup, team management, and RabbitMQ config changes.
4+
allowed-tools: Bash(cloudamqp:*), Bash(jq:*), Bash(cat:*), Bash(echo:*), Bash(chmod:*), Bash(grep:*), Bash(sleep:*)
5+
---
6+
7+
# CloudAMQP CLI
8+
9+
## Quick start
10+
11+
```bash
12+
cloudamqp instance list
13+
cloudamqp instance get --id <id>
14+
cloudamqp instance create --name=<name> --plan=<plan> --region=<region> --wait
15+
cloudamqp instance restart-rabbitmq --id <id>
16+
cloudamqp instance delete --id <id> --force
17+
```
18+
19+
## Authentication
20+
21+
Check auth before running anything — interactive prompts don't work in agent context:
22+
23+
```bash
24+
cat ~/.cloudamqprc 2>/dev/null || echo "not configured"
25+
```
26+
27+
If not configured, ask the user for their API key (from https://customer.cloudamqp.com/apikeys), then:
28+
29+
```bash
30+
echo "<api-key>" > ~/.cloudamqprc
31+
chmod 600 ~/.cloudamqprc
32+
```
33+
34+
Alternatively, set `CLOUDAMQP_APIKEY` in the environment. If neither is set, all commands will fail.
35+
36+
## Output
37+
38+
Read commands (`list`, `get`) support `-o json` for machine-readable output and `-o table` (default) for display. Use `--fields` to select columns. Write commands (`create`, `update`, `invite`, etc.) print plain text — they don't support `-o json`.
39+
40+
## Commands
41+
42+
### Instance lifecycle
43+
44+
```bash
45+
cloudamqp instance create --name=<name> --plan=<plan> --region=<region> [--tags=<tag>...] [--vpc-id=<id>] [--wait] [--wait-timeout=20m]
46+
cloudamqp instance list [--details]
47+
cloudamqp instance get --id <id>
48+
cloudamqp instance update --id <id> [--name=<name>] [--plan=<plan>]
49+
cloudamqp instance delete --id <id> [--force]
50+
cloudamqp instance resize-disk --id <id> --disk-size=<gb> [--allow-downtime]
51+
```
52+
53+
### Copy settings between instances (dedicated only)
54+
55+
```bash
56+
cloudamqp instance create --name=staging --plan=<plan> --region=<region> \
57+
--copy-from-id=<id> --copy-settings=metrics,firewall,config,alarms,logs,definitions,plugins --wait
58+
```
59+
60+
### Node and plugin management
61+
62+
```bash
63+
cloudamqp instance nodes list --id <id>
64+
cloudamqp instance nodes versions --id <id>
65+
cloudamqp instance plugins list --id <id>
66+
```
67+
68+
### RabbitMQ configuration
69+
70+
```bash
71+
cloudamqp instance config list --id <id>
72+
cloudamqp instance config get --id <id> --key <key>
73+
cloudamqp instance config set --id <id> --key <key> --value <value>
74+
```
75+
76+
### Instance actions
77+
78+
```bash
79+
# restarts (rolling for HA clusters)
80+
cloudamqp instance restart-rabbitmq --id <id> [--nodes=node1,node2]
81+
cloudamqp instance restart-cluster --id <id> # full restart, causes downtime
82+
cloudamqp instance restart-management --id <id>
83+
84+
# start/stop
85+
cloudamqp instance start --id <id>
86+
cloudamqp instance stop --id <id>
87+
cloudamqp instance reboot --id <id>
88+
cloudamqp instance start-cluster --id <id>
89+
cloudamqp instance stop-cluster --id <id>
90+
91+
# upgrades — async, return immediately, poll until ready
92+
cloudamqp instance upgrade-erlang --id <id>
93+
cloudamqp instance upgrade-rabbitmq --id <id> --version=<version>
94+
cloudamqp instance upgrade-all --id <id>
95+
cloudamqp instance upgrade-versions --id <id>
96+
```
97+
98+
### VPC management
99+
100+
```bash
101+
cloudamqp vpc create --name=<name> --region=<region> --subnet=<cidr>
102+
cloudamqp vpc list
103+
cloudamqp vpc get --id <id>
104+
cloudamqp vpc update --id <id> --name=<name>
105+
cloudamqp vpc delete --id <id>
106+
```
107+
108+
### Team management
109+
110+
```bash
111+
cloudamqp team list
112+
cloudamqp team invite --email=<email> [--role=<role>] [--tags=<tag>]
113+
cloudamqp team update --user-id=<id> --role=<role>
114+
cloudamqp team remove --email=<email>
115+
```
116+
117+
### Plans, regions, audit
118+
119+
```bash
120+
cloudamqp plans [--backend=rabbitmq|lavinmq] # always fetch, never guess
121+
cloudamqp regions [--provider=<provider>] # always fetch, never guess
122+
cloudamqp audit [--timestamp=2024-01]
123+
cloudamqp rotate-key
124+
```
125+
126+
## Key behaviors
127+
128+
- **Async**: creation, resizes, upgrades return immediately. Use `--wait` on create, or poll `instance get --id <id> -o json | jq -r '.ready'` until `"Yes"`.
129+
- **Destructive commands** prompt for confirmation — use `--force` to skip.
130+
- **Multiple tags**: repeat the flag: `--tags=prod --tags=web`.
131+
- **Plan/region names**: always run `cloudamqp plans` / `cloudamqp regions` first — never hardcode them.
132+
133+
## Reference guides
134+
135+
Read these before tackling the relevant task:
136+
137+
- **Scripting, JSON parsing, batch ops**[references/scripting.md](references/scripting.md)
138+
- **Upgrades, restarts, maintenance workflows**[references/upgrades.md](references/upgrades.md)
139+
- **VPC creation and network setup**[references/vpc-setup.md](references/vpc-setup.md)
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# Scripting and automation
2+
3+
## JSON output for parsing
4+
5+
Read commands (`list`, `get`, `plans`, `regions`) support `-o json`. All values come out as strings.
6+
7+
```bash
8+
# get connection URL for an instance (masked; add --show-url for full URL)
9+
cloudamqp instance get --id <id> -o json | jq -r '.url'
10+
11+
# find instances that aren't ready (requires --details; ready is "Yes"/"No" string)
12+
cloudamqp instance list --details -o json | jq -r '.[] | select(.ready == "No") | "\(.id) \(.name)"'
13+
14+
# get IDs matching a tag (requires --details; tags is a comma-joined string)
15+
cloudamqp instance list --details -o json | jq -r '.[] | select(.tags | split(",") | map(ltrimstr(" ")) | contains(["staging"])) | .id'
16+
```
17+
18+
## Create and capture instance ID
19+
20+
`instance create` prints a human-readable prefix before the JSON, so pipe through `tail -n +2`:
21+
22+
```bash
23+
# fetch a valid plan and region first
24+
PLAN=$(cloudamqp plans --backend=rabbitmq -o json | jq -r '.[0].name')
25+
REGION=$(cloudamqp regions -o json | jq -r '.[0].id')
26+
27+
RESULT=$(cloudamqp instance create --name=temp --plan="$PLAN" --region="$REGION" | tail -n +2)
28+
INSTANCE_ID=$(echo "$RESULT" | jq -r '.id')
29+
```
30+
31+
## Wait for instance readiness
32+
33+
Prefer the built-in flag:
34+
35+
```bash
36+
cloudamqp instance create --name=my-instance --plan=<plan> --region=<region> --wait --wait-timeout=20m
37+
```
38+
39+
Or poll manually:
40+
41+
```bash
42+
while true; do
43+
STATUS=$(cloudamqp instance get --id "$INSTANCE_ID" -o json | jq -r '.ready')
44+
[ "$STATUS" = "Yes" ] && break
45+
sleep 30
46+
done
47+
```
48+
49+
## Skip confirmations in scripts
50+
51+
```bash
52+
cloudamqp instance delete --id <id> --force
53+
cloudamqp vpc delete --id <id> --force
54+
```
55+
56+
## Batch operations
57+
58+
```bash
59+
# restart all instances tagged "staging" (--details required for tags field)
60+
for ID in $(cloudamqp instance list --details -o json | jq -r '.[] | select(.tags | split(",") | map(ltrimstr(" ")) | contains(["staging"])) | .id'); do
61+
cloudamqp instance restart-rabbitmq --id "$ID"
62+
done
63+
```
64+
65+
## Clone an instance with full config
66+
67+
```bash
68+
cloudamqp instance create \
69+
--name=staging-copy \
70+
--plan=<plan> \
71+
--region=<region> \
72+
--copy-from-id=<source-id> \
73+
--copy-settings=alarms,metrics,logs,firewall,config,definitions,plugins \
74+
--wait
75+
```
76+
77+
Only works between dedicated instances (not shared plans).

0 commit comments

Comments
 (0)