Skip to content
Closed
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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
115 changes: 115 additions & 0 deletions .claude/skills/fireblocks-cli/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
---
name: fireblocks-cli
description: Agent-first CLI for Fireblocks infrastructure. Execute any Fireblocks API operation from the command line.
---

# Fireblocks CLI

## Command Pattern
```
fireblocks <namespace> <action> [flags]
```

## Discovery

- `fireblocks help-index` -- compact JSON index of all commands (<2K tokens).
Returns: `{commands: [{namespace, action, description, method?, path?, flags: [{name, type, required}]}]}`
- `fireblocks <namespace> --help` -- list actions in a namespace.
- `fireblocks <namespace> <action> --help` -- show all flags for one command.
- `fireblocks <namespace> <action> --dry-run [flags]` -- preview request (method, url, params, body) without executing.
- `fireblocks whoami` -- verify credentials, calls GET /v1/users/me. Returns masked API key, base URL, and verification status.

## Authentication

Resolution order (highest priority first):
1. CLI flags: `--api-key`, `--secret-key`
2. Env vars: `FIREBLOCKS_API_KEY` + (`FIREBLOCKS_SECRET_KEY` | `FIREBLOCKS_SECRET_KEY_PATH`)
3. Config profile: `~/.config/fireblocks/config.json` (select with `--profile <name>`)
4. Error if no credentials found.

`--secret-key` accepts either an inline PEM string (detected by `-----BEGIN` marker) or a file path.

`fireblocks configure` is interactive-only. Agents must use env vars or flags.

## Flag Conventions

- OpenAPI path params (e.g. `{vaultAccountId}`) become required flags: `--vault-account-id`
- OpenAPI query params become optional flags with the same kebab-case conversion.
- Write ops (POST/PUT/PATCH/DELETE) accept `--data '<json>'` for the request body.
- Write ops that support idempotency accept `--idempotency-key <uuid>` for safe retries.

## Global Flags

| Flag | Env Var | Purpose |
|------|---------|---------|
| `--api-key` | `FIREBLOCKS_API_KEY` | API key |
| `--secret-key` | `FIREBLOCKS_SECRET_KEY` / `FIREBLOCKS_SECRET_KEY_PATH` | RSA private key (PEM or path) |
| `--base-url` | `FIREBLOCKS_BASE_URL` | Override API endpoint (default: `https://api.fireblocks.io`) |
| `--profile` | | Named config profile |
| `--no-confirm` | | Skip write-op confirmation prompt |
| `--dry-run` | | Preview request without executing |
| `--debug` | | Log request/response details to stderr |
| `--json` | | Force structured JSON output (oclif envelope) |

## Non-Interactive Usage

Always pass `--no-confirm` on write operations. The CLI auto-skips prompts when stdin is not a TTY, but explicit `--no-confirm` is safer and self-documenting.

## Output

- **stdout**: JSON data only.
- **stderr**: warnings, beta notices, errors, debug logs.
- `--debug` output on stderr: `[DEBUG] METHOD URL`, `[DEBUG] Body: ...`, `[DEBUG] Response: STATUS`, `[DEBUG] Request-ID: ...`
- Beta commands print to stderr: `Warning: This command is in beta and may change in future releases.` This is informational, not an error.

## Exit Codes

| Code | Meaning | Recovery |
|------|---------|----------|
| 0 | Success | |
| 1 | Client error (400/409/422) | Check request body/params |
| 2 | Usage/parse error | Check flag names and types |
| 3 | Auth error (401/403) | Verify credentials with `fireblocks whoami` |
| 4 | Not found (404) | Verify resource ID exists |
| 5 | Rate limited (429) | Wait `retry_after` seconds from error JSON, then retry |
| 6 | Server error (500+) | Retry after brief delay |
| 7 | Timeout (30s) | Retry; timeout is not configurable |

## Error Format

Errors are JSON on stderr:
```json
{"code": 5, "status": 429, "message": "Rate limit exceeded", "request_id": "abc-123", "retry_after": 30}
```
`request_id` and `retry_after` are present only when applicable.

## Examples
```bash
# List vault accounts
fireblocks vaults get-paged-vault-accounts --json

# Get a specific vault
fireblocks vaults get-vault-account --vault-account-id 0 --json

# Create a transaction (write op: requires --data and --no-confirm)
fireblocks transactions create-transaction \
--data '{"assetId":"BTC","amount":"0.01","source":{"type":"VAULT_ACCOUNT","id":"0"},"destination":{"type":"VAULT_ACCOUNT","id":"1"}}' \
--no-confirm

# Idempotent write with retry safety
fireblocks transactions create-transaction \
--data '{"assetId":"ETH","amount":"1.0","source":{"type":"VAULT_ACCOUNT","id":"0"},"destination":{"type":"ONE_TIME_ADDRESS","oneTimeAddress":{"address":"0x1234"}}}' \
--idempotency-key "$(uuidgen)" --no-confirm

# Preview without executing
fireblocks transactions create-transaction --data '{"assetId":"BTC","amount":"0.01"}' --dry-run

# Debug a failing request
fireblocks vaults get-vault-account --vault-account-id 0 --debug

# Use sandbox environment
fireblocks vaults get-paged-vault-accounts --base-url https://sandbox-api.fireblocks.io --json

# Verify auth setup
fireblocks whoami
```
35 changes: 35 additions & 0 deletions .github/workflows/auto-reply-issue.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: Auto Reply On New Issues
on:
issues:
types: [opened]

jobs:
auto-reply:
runs-on: ubuntu-latest
steps:
- name: Check out repository code
uses: actions/checkout@v4

- name: Choose random reply message
id: choose_message
run: |
reply_messages=(
"Thank you for raising this issue! We will look into it shortly. (Note that this CLI code is auto generated)"
"We appreciate your feedback. Our team will investigate this issue shortly. (Note that this CLI code is auto generated)"
"Your issue has been noted. We'll get back to you soon. (Note that this CLI code is auto generated)"
"Thanks for raising this issue. We'll review it and provide updates soon. (Note that this CLI code is auto generated)"
"Thank you for letting us know about this issue. We'll investigate and get back to you soon. (Note that this CLI code is auto generated)"
"Acknowledged. We'll review the issue and respond soon. (Note that this CLI code is auto generated)"
"Thanks for bringing this to our attention. We'll review it and provide updates soon. (Note that this CLI code is auto generated)"
"We've received your issue. Thanks for your patience. (Note that this CLI code is auto generated)"
"Noted. Expect updates on your issue shortly. (Note that this CLI code is auto generated)"
"Your issue is important to us. We will look into it shortly. (Note that this CLI code is auto generated)"
)
random_index=$((RANDOM % ${#reply_messages[@]}))
echo "message=${reply_messages[$random_index]}" >> $GITHUB_OUTPUT

- name: Reply to issue
run: |
gh issue comment ${{ github.event.issue.number }} --body "${{ steps.choose_message.outputs.message }}"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
36 changes: 36 additions & 0 deletions .github/workflows/auto-reply-pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: Auto Reply On New Pull Requests
on:
pull_request:
types: [opened]

jobs:
auto-reply:
runs-on: ubuntu-latest
steps:
- name: Check out repository code
uses: actions/checkout@v4

- name: Choose random reply message
id: choose_message
run: |
reply_messages=(
"Thank you for raising this! We will review it shortly. (Note that this CLI code is auto generated)"
"We appreciate your contribution. Our team will investigate this request shortly. (Note that this CLI code is auto generated)"
"Your request has been noted. We'll get back to you soon. (Note that this CLI code is auto generated)"
"Thanks for submitting this request. We'll review it and provide updates soon. (Note that this CLI code is auto generated)"
"Thank you for letting us know about this request. We'll investigate and get back to you soon. (Note that this CLI code is auto generated)"
"Acknowledged. We'll review and respond soon. (Note that this CLI code is auto generated)"
"Thanks for bringing this request to our attention. We'll review and provide updates soon. (Note that this CLI code is auto generated)"
"We've received your request. Thanks for your patience. (Note that this CLI code is auto generated)"
"Noted. Expect updates shortly. (Note that this CLI code is auto generated)"
"Your request is important to us. We will look into it shortly. (Note that this CLI code is auto generated)"
)
random_index=$((RANDOM % ${#reply_messages[@]}))
echo "message=${reply_messages[$random_index]}" >> $GITHUB_OUTPUT

- name: Reply to pull request
if: (!contains(fromJSON('["github-actions"]'), github.event.pull_request.user.login))
run: |
gh pr comment ${{ github.event.number }} --body "${{ steps.choose_message.outputs.message }}"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
100 changes: 100 additions & 0 deletions .github/workflows/draft-release-from-pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
name: Draft Release from PR

on:
push:
branches:
- master

permissions:
contents: write
pull-requests: read

jobs:
draft-release:
runs-on: ubuntu-latest

steps:
- name: Generate GitHub App token
id: generate-token
uses: actions/create-github-app-token@v2
with:
app-id: ${{ vars.CLI_GENERATION_APP_ID }}
private-key: ${{ secrets.CLI_GENERATION_APP_PRIVATE_KEY }}

- name: Checkout repository
uses: actions/checkout@v4
with:
token: ${{ steps.generate-token.outputs.token }}

- name: Get last merged PR
env:
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
run: |
gh pr list \
--state merged \
--base master \
--limit 1 \
--json number,title,body,labels \
> pr.json

PR_NUM=$(jq -r '.[0].number // "none"' pr.json)
PR_TITLE=$(jq -r '.[0].title // "none"' pr.json)
echo "Found merged PR: #$PR_NUM - $PR_TITLE"

- name: Get latest release version
env:
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
run: |
LAST_TAG=$(gh release list --limit 1 --json tagName -q '.[0].tagName')

if [[ -z "$LAST_TAG" || "$LAST_TAG" == "null" ]]; then
echo "No existing release found. A release tag is required to calculate the next version."
exit 1
fi

echo "Found latest release: $LAST_TAG"
echo "LAST_TAG=$LAST_TAG" >> $GITHUB_ENV

- name: Calculate next version from labels
run: |
V="${LAST_TAG#v}"

MAJOR=$(echo $V | cut -d. -f1)
MINOR=$(echo $V | cut -d. -f2)
PATCH=$(echo $V | cut -d. -f3)

LABELS=$(jq -r '.[0].labels[].name' pr.json)
echo "Found labels: $LABELS"

if echo "$LABELS" | grep -q "major"; then
echo "Bumping MAJOR version"
MAJOR=$((MAJOR+1))
MINOR=0
PATCH=0
elif echo "$LABELS" | grep -q "minor"; then
echo "Bumping MINOR version"
MINOR=$((MINOR+1))
PATCH=0
else
echo "Bumping PATCH version"
PATCH=$((PATCH+1))
fi

echo "Calculated next version: v$MAJOR.$MINOR.$PATCH"
echo "VERSION=v$MAJOR.$MINOR.$PATCH" >> $GITHUB_ENV

- name: Create DRAFT release using PR BODY
env:
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
run: |
PR_BODY=$(jq -r '.[0].body // ""' pr.json)

echo "Creating draft release..."
echo "Version: $VERSION"

gh release create "$VERSION" \
--draft \
--title "$VERSION" \
--notes "$PR_BODY"

echo "Draft release created successfully!"
Loading
Loading