-
Notifications
You must be signed in to change notification settings - Fork 1
Add Claude Code skill and install command #43
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
d1e24b0
544ed4c
6501c75
d78d3f8
55d115a
fb35cbb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| package cmd | ||
|
|
||
| import ( | ||
| "embed" | ||
| "fmt" | ||
| "io/fs" | ||
| "os" | ||
| "path/filepath" | ||
| "strings" | ||
|
|
||
| "github.com/spf13/cobra" | ||
| ) | ||
|
|
||
| //go:embed all:skills | ||
| var skillsFS embed.FS | ||
|
|
||
| var installCmd = &cobra.Command{ | ||
| Use: "install", | ||
| Short: "Install integrations", | ||
| } | ||
|
|
||
| var installSkillsCmd = &cobra.Command{ | ||
| Use: "skills", | ||
| Short: "Install Claude Code skills to ~/.claude/skills/", | ||
| Args: cobra.NoArgs, | ||
| Long: `Install the CloudAMQP CLI skills for Claude Code. | ||
|
|
||
| Skills teach Claude how to use the cloudamqp CLI. After installation, | ||
| Claude Code will automatically discover and use them. | ||
|
|
||
| Skills are installed to: ~/.claude/skills/cloudamqp-cli/`, | ||
| RunE: func(cmd *cobra.Command, args []string) error { | ||
| home, err := os.UserHomeDir() | ||
| if err != nil { | ||
| return fmt.Errorf("could not determine home directory: %w", err) | ||
| } | ||
| dest := filepath.Join(home, ".claude", "skills", "cloudamqp-cli") | ||
|
|
||
| const embedPrefix = "skills/cloudamqp-cli" | ||
| err = fs.WalkDir(skillsFS, embedPrefix, func(path string, d fs.DirEntry, err error) error { | ||
| if err != nil { | ||
| return err | ||
| } | ||
| // Embedded paths always use forward slashes. Use strings.TrimPrefix | ||
| // then filepath.FromSlash so this works correctly on Windows too. | ||
| rel := strings.TrimPrefix(strings.TrimPrefix(path, embedPrefix), "/") | ||
| target := filepath.Join(dest, filepath.FromSlash(rel)) | ||
| if d.IsDir() { | ||
| return os.MkdirAll(target, 0755) | ||
| } | ||
| data, err := skillsFS.ReadFile(path) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| return os.WriteFile(target, data, 0644) | ||
| }) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to install skills: %w", err) | ||
| } | ||
| fmt.Printf("Skills installed to %s\n", dest) | ||
| return nil | ||
| }, | ||
|
Comment on lines
+22
to
+62
|
||
| } | ||
|
|
||
| func init() { | ||
| installCmd.AddCommand(installSkillsCmd) | ||
| rootCmd.AddCommand(installCmd) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| package cmd | ||
|
|
||
| import ( | ||
| "path/filepath" | ||
| "testing" | ||
|
|
||
| "github.com/stretchr/testify/assert" | ||
| "github.com/stretchr/testify/require" | ||
| ) | ||
|
|
||
| func TestInstallSkillsCmd(t *testing.T) { | ||
| home := t.TempDir() | ||
| t.Setenv("HOME", home) | ||
|
|
||
| err := installSkillsCmd.RunE(installSkillsCmd, []string{}) | ||
| require.NoError(t, err) | ||
|
|
||
| base := filepath.Join(home, ".claude", "skills", "cloudamqp-cli") | ||
| assert.FileExists(t, filepath.Join(base, "SKILL.md")) | ||
| assert.FileExists(t, filepath.Join(base, "references", "scripting.md")) | ||
| assert.FileExists(t, filepath.Join(base, "references", "upgrades.md")) | ||
| assert.FileExists(t, filepath.Join(base, "references", "vpc-setup.md")) | ||
| } | ||
|
|
||
| func TestInstallSkillsCmd_NoArgs(t *testing.T) { | ||
| err := installSkillsCmd.Args(installSkillsCmd, []string{"unexpected"}) | ||
| assert.Error(t, err) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,139 @@ | ||
| --- | ||
| name: cloudamqp-cli | ||
| 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. | ||
| allowed-tools: Bash(cloudamqp:*), Bash(jq:*), Bash(cat:*), Bash(echo:*), Bash(chmod:*), Bash(grep:*), Bash(sleep:*) | ||
| --- | ||
|
|
||
| # CloudAMQP CLI | ||
|
|
||
| ## Quick start | ||
|
|
||
| ```bash | ||
| cloudamqp instance list | ||
| cloudamqp instance get --id <id> | ||
| cloudamqp instance create --name=<name> --plan=<plan> --region=<region> --wait | ||
| cloudamqp instance restart-rabbitmq --id <id> | ||
| cloudamqp instance delete --id <id> --force | ||
| ``` | ||
|
|
||
| ## Authentication | ||
|
|
||
| Check auth before running anything — interactive prompts don't work in agent context: | ||
|
|
||
| ```bash | ||
| cat ~/.cloudamqprc 2>/dev/null || echo "not configured" | ||
| ``` | ||
|
|
||
| If not configured, ask the user for their API key (from https://customer.cloudamqp.com/apikeys), then: | ||
|
|
||
| ```bash | ||
| echo "<api-key>" > ~/.cloudamqprc | ||
| chmod 600 ~/.cloudamqprc | ||
| ``` | ||
|
|
||
| Alternatively, set `CLOUDAMQP_APIKEY` in the environment. If neither is set, all commands will fail. | ||
|
|
||
| ## Output | ||
|
|
||
| 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`. | ||
|
|
||
| ## Commands | ||
|
|
||
| ### Instance lifecycle | ||
|
|
||
| ```bash | ||
| cloudamqp instance create --name=<name> --plan=<plan> --region=<region> [--tags=<tag>...] [--vpc-id=<id>] [--wait] [--wait-timeout=20m] | ||
| cloudamqp instance list [--details] | ||
| cloudamqp instance get --id <id> | ||
| cloudamqp instance update --id <id> [--name=<name>] [--plan=<plan>] | ||
| cloudamqp instance delete --id <id> [--force] | ||
| cloudamqp instance resize-disk --id <id> --disk-size=<gb> [--allow-downtime] | ||
| ``` | ||
|
|
||
| ### Copy settings between instances (dedicated only) | ||
|
|
||
| ```bash | ||
| cloudamqp instance create --name=staging --plan=<plan> --region=<region> \ | ||
| --copy-from-id=<id> --copy-settings=metrics,firewall,config,alarms,logs,definitions,plugins --wait | ||
| ``` | ||
|
|
||
| ### Node and plugin management | ||
|
|
||
| ```bash | ||
| cloudamqp instance nodes list --id <id> | ||
| cloudamqp instance nodes versions --id <id> | ||
| cloudamqp instance plugins list --id <id> | ||
| ``` | ||
|
|
||
| ### RabbitMQ configuration | ||
|
|
||
| ```bash | ||
| cloudamqp instance config list --id <id> | ||
| cloudamqp instance config get --id <id> --key <key> | ||
| cloudamqp instance config set --id <id> --key <key> --value <value> | ||
| ``` | ||
|
|
||
| ### Instance actions | ||
|
|
||
| ```bash | ||
| # restarts (rolling for HA clusters) | ||
| cloudamqp instance restart-rabbitmq --id <id> [--nodes=node1,node2] | ||
| cloudamqp instance restart-cluster --id <id> # full restart, causes downtime | ||
| cloudamqp instance restart-management --id <id> | ||
|
|
||
| # start/stop | ||
| cloudamqp instance start --id <id> | ||
| cloudamqp instance stop --id <id> | ||
| cloudamqp instance reboot --id <id> | ||
| cloudamqp instance start-cluster --id <id> | ||
| cloudamqp instance stop-cluster --id <id> | ||
|
|
||
| # upgrades — async, return immediately, poll until ready | ||
| cloudamqp instance upgrade-erlang --id <id> | ||
| cloudamqp instance upgrade-rabbitmq --id <id> --version=<version> | ||
| cloudamqp instance upgrade-all --id <id> | ||
| cloudamqp instance upgrade-versions --id <id> | ||
| ``` | ||
|
|
||
| ### VPC management | ||
|
|
||
| ```bash | ||
| cloudamqp vpc create --name=<name> --region=<region> --subnet=<cidr> | ||
| cloudamqp vpc list | ||
| cloudamqp vpc get --id <id> | ||
| cloudamqp vpc update --id <id> --name=<name> | ||
| cloudamqp vpc delete --id <id> | ||
| ``` | ||
|
|
||
| ### Team management | ||
|
|
||
| ```bash | ||
| cloudamqp team list | ||
| cloudamqp team invite --email=<email> [--role=<role>] [--tags=<tag>] | ||
| cloudamqp team update --user-id=<id> --role=<role> | ||
| cloudamqp team remove --email=<email> | ||
| ``` | ||
|
|
||
| ### Plans, regions, audit | ||
|
|
||
| ```bash | ||
| cloudamqp plans [--backend=rabbitmq|lavinmq] # always fetch, never guess | ||
| cloudamqp regions [--provider=<provider>] # always fetch, never guess | ||
| cloudamqp audit [--timestamp=2024-01] | ||
| cloudamqp rotate-key | ||
| ``` | ||
|
|
||
| ## Key behaviors | ||
|
|
||
| - **Async**: creation, resizes, upgrades return immediately. Use `--wait` on create, or poll `instance get --id <id> -o json | jq -r '.ready'` until `"Yes"`. | ||
| - **Destructive commands** prompt for confirmation — use `--force` to skip. | ||
| - **Multiple tags**: repeat the flag: `--tags=prod --tags=web`. | ||
| - **Plan/region names**: always run `cloudamqp plans` / `cloudamqp regions` first — never hardcode them. | ||
|
|
||
| ## Reference guides | ||
|
|
||
| Read these before tackling the relevant task: | ||
|
|
||
| - **Scripting, JSON parsing, batch ops** → [references/scripting.md](references/scripting.md) | ||
| - **Upgrades, restarts, maintenance workflows** → [references/upgrades.md](references/upgrades.md) | ||
| - **VPC creation and network setup** → [references/vpc-setup.md](references/vpc-setup.md) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| # Scripting and automation | ||
|
|
||
| ## JSON output for parsing | ||
|
|
||
| Read commands (`list`, `get`, `plans`, `regions`) support `-o json`. All values come out as strings. | ||
|
|
||
| ```bash | ||
| # get connection URL for an instance (masked; add --show-url for full URL) | ||
| cloudamqp instance get --id <id> -o json | jq -r '.url' | ||
|
|
||
| # find instances that aren't ready (requires --details; ready is "Yes"/"No" string) | ||
| cloudamqp instance list --details -o json | jq -r '.[] | select(.ready == "No") | "\(.id) \(.name)"' | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
|
||
| # get IDs matching a tag (requires --details; tags is a comma-joined string) | ||
| cloudamqp instance list --details -o json | jq -r '.[] | select(.tags | split(",") | map(ltrimstr(" ")) | contains(["staging"])) | .id' | ||
| ``` | ||
|
|
||
| ## Create and capture instance ID | ||
|
|
||
| `instance create` prints a human-readable prefix before the JSON, so pipe through `tail -n +2`: | ||
|
|
||
| ```bash | ||
| # fetch a valid plan and region first | ||
| PLAN=$(cloudamqp plans --backend=rabbitmq -o json | jq -r '.[0].name') | ||
| REGION=$(cloudamqp regions -o json | jq -r '.[0].id') | ||
|
|
||
| RESULT=$(cloudamqp instance create --name=temp --plan="$PLAN" --region="$REGION" | tail -n +2) | ||
| INSTANCE_ID=$(echo "$RESULT" | jq -r '.id') | ||
| ``` | ||
|
|
||
| ## Wait for instance readiness | ||
|
|
||
| Prefer the built-in flag: | ||
|
|
||
| ```bash | ||
| cloudamqp instance create --name=my-instance --plan=<plan> --region=<region> --wait --wait-timeout=20m | ||
| ``` | ||
|
|
||
| Or poll manually: | ||
|
|
||
| ```bash | ||
| while true; do | ||
| STATUS=$(cloudamqp instance get --id "$INSTANCE_ID" -o json | jq -r '.ready') | ||
| [ "$STATUS" = "Yes" ] && break | ||
| sleep 30 | ||
| done | ||
| ``` | ||
|
|
||
| ## Skip confirmations in scripts | ||
|
|
||
| ```bash | ||
| cloudamqp instance delete --id <id> --force | ||
| cloudamqp vpc delete --id <id> --force | ||
| ``` | ||
|
|
||
| ## Batch operations | ||
|
|
||
| ```bash | ||
| # restart all instances tagged "staging" (--details required for tags field) | ||
| for ID in $(cloudamqp instance list --details -o json | jq -r '.[] | select(.tags | split(",") | map(ltrimstr(" ")) | contains(["staging"])) | .id'); do | ||
| cloudamqp instance restart-rabbitmq --id "$ID" | ||
| done | ||
| ``` | ||
|
|
||
| ## Clone an instance with full config | ||
|
|
||
| ```bash | ||
| cloudamqp instance create \ | ||
| --name=staging-copy \ | ||
| --plan=<plan> \ | ||
| --region=<region> \ | ||
| --copy-from-id=<source-id> \ | ||
| --copy-settings=alarms,metrics,logs,firewall,config,definitions,plugins \ | ||
| --wait | ||
| ``` | ||
|
|
||
| Only works between dedicated instances (not shared plans). | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider setting
Args: cobra.NoArgsoninstallSkillsCmd(and possiblyinstallCmd) to match the rest of the CLI commands and to avoid silently accepting unexpected positional arguments (e.g.cloudamqp install skills extra).