From 8cec809e9f3253d9b08f0d606de8e382cf27d420 Mon Sep 17 00:00:00 2001 From: alvseven Date: Mon, 4 May 2026 14:55:14 -0300 Subject: [PATCH 1/2] add api-sync automation: ai-assisted CLI updates from API changes - New CLAUDE.md documents command structure, naming conventions, and the decision rules for translating API changes into CLI changes (when to add/remove commands, add flags, update columns, etc). - New .github/workflows/api-sync.yml triggers on repository_dispatch api-sync, fetches the changelog from the api-sync-data branch, runs Claude Code with CLAUDE.md as context, and opens a PR on the api-sync branch with the resulting changes. --- .github/workflows/api-sync.yml | 132 ++++++++++++++++++++++++++++++++ CLAUDE.md | 134 +++++++++++++++++++++++++++++++++ 2 files changed, 266 insertions(+) create mode 100644 .github/workflows/api-sync.yml create mode 100644 CLAUDE.md diff --git a/.github/workflows/api-sync.yml b/.github/workflows/api-sync.yml new file mode 100644 index 0000000..0d5c326 --- /dev/null +++ b/.github/workflows/api-sync.yml @@ -0,0 +1,132 @@ +name: API Sync + +on: + repository_dispatch: + types: [api-sync] + +permissions: + contents: write + pull-requests: write + id-token: write + +jobs: + sync: + name: Sync CLI with API changes + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: oven-sh/setup-bun@v2 + with: + bun-version: latest + + - name: Fetch API sync data + run: | + mkdir -p /tmp/api-sync + git fetch origin api-sync-data + git show origin/api-sync-data:.api-sync/changelog.md > /tmp/api-sync/changelog.md + echo "=== Changelog ===" + cat /tmp/api-sync/changelog.md + + - name: Check for existing api-sync PR + id: check-pr + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + PR_NUMBER=$(gh pr list --head api-sync --json number --jq '.[0].number // empty') + if [ -n "$PR_NUMBER" ]; then + echo "existing_pr=$PR_NUMBER" >> $GITHUB_OUTPUT + echo "Found existing api-sync PR: #$PR_NUMBER" + else + echo "existing_pr=" >> $GITHUB_OUTPUT + echo "No existing api-sync PR found" + fi + + - name: Create or checkout api-sync branch + run: | + git fetch origin api-sync 2>/dev/null || true + if git rev-parse --verify origin/api-sync >/dev/null 2>&1; then + git checkout api-sync + git reset --hard origin/main + else + git checkout -b api-sync + fi + + - name: Install dependencies + run: bun install --frozen-lockfile + + - name: Apply changes with Claude Code + uses: anthropics/claude-code-action@v1 + with: + claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} + claude_args: '--model claude-sonnet-4-20250514 --allowedTools "Bash(*),Read,Edit,Write,Glob,Grep"' + prompt: | + You are updating this CLI to match BlindPay API changes. + + Read CLAUDE.md in this repo first — it describes the file + layout, command naming conventions, output patterns, and the + decision rules for translating API changes into CLI changes. + + The changelog is at /tmp/api-sync/changelog.md. It is the + authoritative list of API changes since the last sync. + + Process: + 1. Read CLAUDE.md thoroughly. + 2. Read /tmp/api-sync/changelog.md. + 3. For each change, apply the decision rules in CLAUDE.md + (section "Sync workflow conventions"). Skip changes that + don't map to any CLI surface — silence is fine. + 4. Implement the chosen changes: + - New commands: add the action function to + src/commands/resources.ts and wire it into + src/index.ts under the right group banner. + - New flags: add to the option list in src/index.ts and + pass through to the action in src/commands/resources.ts. + - Removed endpoints: remove the command and the action. + - Enum changes: only update help text in src/index.ts. + 5. Bump CLI_VERSION in src/utils/constants.ts (patch for + additive changes, minor if anything was removed). + 6. Run `bun run typecheck` and `bun run lint:fix`. Fix any + errors until both are clean. + 7. Do NOT touch .github/workflows/. + 8. Do NOT create commits — leave changes in the working tree. + + If a change is ambiguous, leave a TODO comment with + `// TODO(api-sync):` so a human reviewer can address it. + + - name: Commit and push + id: commit + run: | + git remote set-url origin "https://x-access-token:${{ secrets.SDK_SYNC_PAT }}@github.com/${{ github.repository }}.git" + git checkout -- .github/workflows/ 2>/dev/null || true + git add -A + git reset HEAD .github/workflows/ 2>/dev/null || true + if git diff --staged --quiet; then + echo "No changes to commit" + echo "has_changes=false" >> $GITHUB_OUTPUT + exit 0 + fi + echo "has_changes=true" >> $GITHUB_OUTPUT + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git commit -m "feat: sync CLI with API changes" + git push --force-with-lease origin api-sync + + - name: Create or update PR + if: steps.commit.outputs.has_changes == 'true' + env: + GH_TOKEN: ${{ secrets.SDK_SYNC_PAT }} + run: | + EXISTING_PR="${{ steps.check-pr.outputs.existing_pr }}" + + if [ -n "$EXISTING_PR" ]; then + echo "Updating existing PR #$EXISTING_PR" + gh pr comment "$EXISTING_PR" --body "Updated with latest API changes." + else + gh pr create \ + --title "feat: sync CLI with API changes" \ + --body "Automated CLI update from API changes." \ + --base main \ + --head api-sync \ + --label api-sync + fi diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..a81dbf3 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,134 @@ +# BlindPay CLI - Agent Reference + +## Commands + +``` +bun run dev # Run CLI directly from source +bun run build # Bundle to dist/index.js +bun run typecheck # tsc --noEmit +bun run lint # oxlint +bun run lint:fix # oxlint --fix +bun run test # bun test +``` + +## How updates work + +This CLI is auto-synced with the BlindPay API. When SDK-eligible +(`x-sdk: true`) routes change upstream, the workflow at +`.github/workflows/api-sync.yml` fires: + +1. The blindpay-v2 `sdk-sync.yml` workflow generates a markdown changelog + from the OpenAPI spec diff and pushes it to this repo's + `api-sync-data` branch at `.api-sync/changelog.md`. It then fires a + `repository_dispatch` `api-sync` event. +2. `api-sync.yml` consumes the event, runs Claude with the changelog as + input, and asks Claude to read this CLAUDE.md plus the codebase to + decide what (if any) CLI changes are needed. +3. A PR is opened/updated on the `api-sync` branch for human review. + +Note: not every API change needs a CLI change. The CLI is hand-curated +UX — only commands a human would actually want to run from a terminal. + +## Project structure + +``` +src/ + index.ts # commander program: top-level commands and + # subcommand wiring. One Command per resource. + commands/ + resources.ts # All resource action implementations. + # Each exported function = one command action. + schema.ts # listSchemas, getSchema commands. + utils/ + api-client.ts # apiGet/apiPost/apiPut/apiDelete wrappers + # over fetch, plus resolveContext(). + config.ts # ~/.config/blindpay/config.json read/write. + output.ts # formatOutput(data, json, columns?) for + # table vs JSON rendering. + constants.ts # CLI_VERSION, DEFAULT_API_URL. +``` + +## Conventions + +### Adding a new command + +1. Add an exported async function to `src/commands/resources.ts` (or a + new module if it's a brand new resource). Naming pattern: + `` — `listReceivers`, `getPayout`, `createBankAccount`, + `deleteWebhookEndpoint`. +2. Wire it in `src/index.ts` under the appropriate `program.command(...)` + group. Keep groups together with a banner comment + (`// ── Resource ─────────────────────────────────────`). +3. Add `--json` to any read-only command. Use `printResult(data, json, + columns)` to render — pass meaningful columns for the default + non-JSON output. +4. Path params (e.g. ``, ``) are positional or + `--receiver-id ` flags depending on whether they belong to the + primary resource being acted on. Look at how existing commands handle + parent IDs (bank_accounts uses `--receiver-id`). +5. Wrap all API calls with `try/catch` and route errors through + `handleApiError(err, json)`. +6. Use `parseAmount(...)` (already in resources.ts) for any amount field + to enforce non-negative integers (cents). + +### Naming + +| API path | Command | +| ----------------------------------------------------- | -------------------------------- | +| `GET /v1/instances/{id}/receivers` | `blindpay receivers list` | +| `POST /v1/instances/{id}/receivers/{rid}/bank-accounts` | `blindpay bank_accounts create` | +| `GET /v1/available/...` | `blindpay available rails` | + +Group names use `snake_case` (matching the API resource name with +hyphens replaced by underscores), command names use kebab/lowercase. + +### Output + +Default output is a small terminal table built by `formatOutput`. Pass +explicit `columns` so the default view shows the most useful 4–6 fields, +not every field. `--json` always prints the full object as `JSON.stringify(_, null, 2)`. + +### Errors + +`handleApiError` already formats API validation errors, status codes, +and unknown errors. Don't roll your own. + +`exitWithError(message, exitCode, json)` is for client-side validation +failures (bad CLI flags etc). + +### Prompts + +We do not use interactive prompts for CLI commands today — every input +is a flag. Don't introduce `clack.prompt` mid-command unless the user +explicitly opts in via `--interactive` or similar. + +### Linting + +`oxlint` enforces formatting and lint. Run `bun run lint:fix` after +edits and ensure `bun run typecheck` is clean before opening a PR. + +## Sync workflow conventions + +When responding to an api-sync event: + +1. Read `.api-sync/changelog.md`. It lists every API change since the + last sync. +2. For each change, decide: + - **New endpoint** → Add a CLI command only if a terminal user is + plausibly going to run it. Usually yes for CRUD-style endpoints, + no for internal/read-only diagnostics. When in doubt, add it. + - **New field on an input** → Add a corresponding `--` flag + to the command's option list and pass it through. + - **New field on an output** → Update the default `columns` array if + the field is interesting; don't add columns for low-signal fields. + - **Removed endpoint/field** → Remove the corresponding command/flag. + - **Enum value added** → Update help text only (CLI doesn't validate + enum values client-side). +3. Bump CLI version in `src/utils/constants.ts` (`CLI_VERSION`) — patch + for additive changes, minor if you removed anything. +4. Run `bun run typecheck` and `bun run lint:fix`. Fix any errors. +5. Do NOT touch `.github/workflows/`. +6. Do NOT create commits — leave changes in the working tree. + +If a change in the changelog doesn't map to any CLI surface (e.g. a +schema-only change with no field added), skip it silently. From 26d1c88bf0b8c6599ef2a1bb54faa03482982059 Mon Sep 17 00:00:00 2001 From: alvseven Date: Wed, 6 May 2026 15:00:11 -0300 Subject: [PATCH 2/2] bump model to claude-sonnet-4-6, run tests in api-sync flow --- .github/workflows/api-sync.yml | 6 +++--- CLAUDE.md | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/api-sync.yml b/.github/workflows/api-sync.yml index 0d5c326..dcfe452 100644 --- a/.github/workflows/api-sync.yml +++ b/.github/workflows/api-sync.yml @@ -59,7 +59,7 @@ jobs: uses: anthropics/claude-code-action@v1 with: claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} - claude_args: '--model claude-sonnet-4-20250514 --allowedTools "Bash(*),Read,Edit,Write,Glob,Grep"' + claude_args: '--model claude-sonnet-4-6 --allowedTools "Bash(*),Read,Edit,Write,Glob,Grep"' prompt: | You are updating this CLI to match BlindPay API changes. @@ -86,8 +86,8 @@ jobs: - Enum changes: only update help text in src/index.ts. 5. Bump CLI_VERSION in src/utils/constants.ts (patch for additive changes, minor if anything was removed). - 6. Run `bun run typecheck` and `bun run lint:fix`. Fix any - errors until both are clean. + 6. Run `bun run typecheck`, `bun run lint:fix`, and + `bun run test`. Fix any errors until all three are clean. 7. Do NOT touch .github/workflows/. 8. Do NOT create commits — leave changes in the working tree. diff --git a/CLAUDE.md b/CLAUDE.md index a81dbf3..18f0c95 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -126,7 +126,7 @@ When responding to an api-sync event: enum values client-side). 3. Bump CLI version in `src/utils/constants.ts` (`CLI_VERSION`) — patch for additive changes, minor if you removed anything. -4. Run `bun run typecheck` and `bun run lint:fix`. Fix any errors. +4. Run `bun run typecheck`, `bun run lint:fix`, and `bun run test`. Fix any errors. 5. Do NOT touch `.github/workflows/`. 6. Do NOT create commits — leave changes in the working tree.