---
name: tidbcloud-api
description: |
  Interact with TiDB Cloud TiDBX APIs for Starter, Essential, and Premium tiers.
  Use when user asks to create, delete, list, or manage TiDB Cloud clusters,
  run SQL against TiDB Cloud databases, manage backups, or explore TiDB Cloud
  OpenAPI operations. Trigger phrases: "create a tidbx cluster",
  "delete my tidb cloud cluster", "list clusters", "tidbx req:",
  "tidb cloud API", "manage tidb premium cluster", "explore tidbcloud openapi".
  Do NOT use for Dedicated tier clusters or general database questions unrelated
  to TiDB Cloud management.
---

# TiDB Cloud API

Operate TiDB Cloud TiDBX (Starter, Essential, Premium) clusters via shell scripts
that wrap `curl` with digest authentication. Credentials never appear in agent output.

## SUT Selection (Which API Target)

Pick the SUT based on what the user says:

| User Intent | SUT Flag | API Host | Entity |
|-------------|----------|----------|--------|
| No tier mentioned (default) | `--sut tidbx` | `serverless.tidbapi.com/v1beta1` | cluster |
| Explicitly says **Premium** | `--sut tidbx-premium` | `cloud.tidbapi.com/v1beta2` | tidb |
| Explicitly says **Dedicated** | Not supported by this skill | - | - |

Key differences between Starter/Essential and Premium:
- Different hosts and base paths
- Different entity names: `cluster` (Starter/Essential) vs `tidb` (Premium)
- Different operationId prefixes: `ClusterService_*` vs `TidbService_*`

## Execution Strategy

1. Try a **fast path** if the request matches a common operation (see below).
2. Otherwise use the **OpenAPI selector** (list -> extract -> execute).
3. Only if you still cannot execute after 3 iterations, read the OpenAPI spec
   directly from `references/` as a last resort.

## Safety Rules

- Do **not** print/echo secrets (API keys, passwords). Use `${ENV_VAR}` placeholders.
- Do **not** modify files in this skill directory unless the user explicitly asks.
- Prefer autonomy: only ask the user when the request is ambiguous.
  - If the user explicitly requested create/delete with enough identifiers, execute.
  - Ask only when multiple matches exist or required inputs are missing.

## Scripts

All scripts live in `scripts/` relative to this skill directory.

| Script | Purpose |
|--------|---------|
| `scripts/tidbcloud-exec.sh http '<json>' --sut <sut>` | Execute one HTTP request |
| `scripts/tidbcloud-exec.sh poll '<json>' --sut <sut>` | Poll until condition met |
| `scripts/tidbcloud-openapi.sh list --sut <sut> --query <kw>` | List matching operations |
| `scripts/tidbcloud-openapi.sh extract --sut <sut> --operation-id <id>` | Extract one operation spec |

For auth setup, see `references/credentials.md`.

## Fast Paths

### Starter/Essential: Create Cluster

1. Show a redacted summary (name / region / project) and proceed if user asked to create.
2. Create with `POST /clusters` (`ClusterService_CreateCluster`).
3. Save `clusterId` from response.
4. Poll `GET /clusters/{clusterId}` until `state == ACTIVE`.

**Tier rules:**
- No tier mentioned -> Starter (omit `autoScaling`)
- User says Essential -> include `"autoScaling": {"minRcu": 2000, "maxRcu": 4000}`

```bash
scripts/tidbcloud-exec.sh http '{
  "method":"POST",
  "path":"/clusters",
  "body":{
    "displayName":"<name>",
    "labels":{"tidb.cloud/project":"${TIDBCLOUD_PROJECT_ID}"},
    "region":{"name":"${TIDBCLOUD_REGION_NAME:-regions/aws-us-east-1}"},
    "rootPassword":"${TIDBCLOUD_ROOT_PASSWORD:-}"
  }
}' --sut tidbx
```

Then poll:
```bash
scripts/tidbcloud-exec.sh poll '{
  "method":"GET",
  "path":"/clusters/<clusterId>",
  "expect":"body.state == ACTIVE",
  "max_retries":60,
  "delay":10
}' --sut tidbx
```

### Starter/Essential: Delete Cluster

- If a `clusterId` exists from this conversation, delete that.
- Otherwise: list clusters (`GET /clusters`), show numbered list, delete by ID.

```bash
scripts/tidbcloud-exec.sh http '{"method":"DELETE","path":"/clusters/<clusterId>"}' --sut tidbx
```

### Premium: Create Cluster

1. Show redacted summary (name / region / maxRcu) and proceed.
2. Create with `POST /tidbs` (`TidbService_CreateTidb`).
3. Save `tidbId` from response.
4. Poll `GET /tidbs/{tidbId}` until `state == ACTIVE`.

Required body fields:
- `displayName`: 4-64 chars, `^[A-Za-z0-9][-A-Za-z0-9]{2,62}[A-Za-z0-9]$`
- `regionId`: `{cloud}-{region}` (e.g. `aws-us-east-1`)
- `maxRcu`: string (e.g. `"8000"`)
- `servicePlan`: `"Premium"`

```bash
scripts/tidbcloud-exec.sh http '{
  "method":"POST",
  "path":"/tidbs",
  "body":{
    "displayName":"<name>",
    "regionId":"${TIDBCLOUD_PREMIUM_REGION_ID:-aws-us-east-1}",
    "maxRcu":"8000",
    "servicePlan":"Premium",
    "rootPassword":"${TIDBCLOUD_ROOT_PASSWORD:-}"
  }
}' --sut tidbx-premium
```

Then poll:
```bash
scripts/tidbcloud-exec.sh poll '{
  "method":"GET",
  "path":"/tidbs/<tidbId>",
  "expect":"body.state == ACTIVE",
  "max_retries":60,
  "delay":10
}' --sut tidbx-premium
```

### Premium: Create Cluster with CMEK

CMEK (Customer Managed Encryption Key) enables dual-layer data encryption using
a customer-provided AWS KMS key.

**Prerequisite:** Get the TiDB Cloud IAM principal that needs KMS key access:

```bash
scripts/tidbcloud-exec.sh http '{
  "method":"GET",
  "path":"/cmeks:principal?servicePlan=Premium&regionId=aws-us-east-1"
}' --sut tidbx-premium
```

Returns `aws.accountId` (e.g. `886436925895`). The customer's KMS key policy must
grant this account `kms:Encrypt`, `kms:Decrypt`, `kms:GenerateDataKey*`,
`kms:ReEncrypt*`, `kms:DescribeKey`, `kms:CreateGrant`.

**Known spec bug:** The `awsPrincipal` field inside the CMEK block is **required
by the server** but the OpenAPI spec marks `accountId` as `readOnly` and does not
list `awsPrincipal` in the `required` array. You **must** include `awsPrincipal`
with the `accountId` from the principal endpoint above, otherwise the server
returns a misleading 400 error:
`"Customer managed encryption key (CMEK) is only supported for AWS cloud provider with Premium service plan."`

```bash
scripts/tidbcloud-exec.sh http '{
  "method":"POST",
  "path":"/tidbs",
  "body":{
    "displayName":"<name>",
    "regionId":"${TIDBCLOUD_PREMIUM_REGION_ID:-aws-us-east-1}",
    "maxRcu":"8000",
    "servicePlan":"Premium",
    "rootPassword":"${TIDBCLOUD_ROOT_PASSWORD:-}",
    "dualLayerDataEncryption":{
      "cmek":{
        "regionId":"${TIDBCLOUD_PREMIUM_REGION_ID:-aws-us-east-1}",
        "servicePlan":"Premium",
        "awsKms":{
          "kmsKeyArn":"<KMS_KEY_ARN>"
        },
        "awsPrincipal":{
          "accountId":"<ACCOUNT_ID_FROM_PRINCIPAL_ENDPOINT>"
        }
      }
    }
  }
}' --sut tidbx-premium
```

Then poll:
```bash
scripts/tidbcloud-exec.sh poll '{
  "method":"GET",
  "path":"/tidbs/<tidbId>",
  "expect":"body.state == ACTIVE",
  "max_retries":60,
  "delay":10
}' --sut tidbx-premium
```

### Premium: Delete Cluster

- If a `tidbId` exists from this conversation, delete that.
- Otherwise: list tidbs (`GET /tidbs?servicePlan=Premium`), show list, delete by ID.

```bash
scripts/tidbcloud-exec.sh http '{"method":"DELETE","path":"/tidbs/<tidbId>"}' --sut tidbx-premium
```

### Premium: Other Operations

Premium also supports: reset root password, cloud provider info, estimate price,
backup policies, backup settings, list/delete backups, restore, CA certificate,
and CMEK operations. Use the OpenAPI selector with `--sut tidbx-premium`.

## OpenAPI Selector (General Operations)

Use when the request is not covered by fast paths.

### Step 1: List candidate operations

```bash
scripts/tidbcloud-openapi.sh list --sut <SUT> --query "<keywords>" --limit 50
```

Pick the most relevant `operationId`. If multiple are plausible, ask the user.

### Step 2: Extract one operation

```bash
scripts/tidbcloud-openapi.sh extract --sut <SUT> --operation-id <OPERATION_ID>
```

This returns the operation spec with all referenced schema definitions resolved.

### Step 3: Execute

Build the HTTP request JSON from the extracted schema, then:

```bash
scripts/tidbcloud-exec.sh http '<request_json>' --sut <SUT>
```

Retry up to 3 iterations (adjust request based on errors / missing fields).
If still failing, read the spec files directly as a last resort:
- Starter/Essential: `references/tidbx/openapi.json`
- Premium: `references/tidbx-premium/tidb.swagger.json` and `references/tidbx-premium/cmek.swagger.json`

## SQL Execution

If the user asks to run SQL, use `mysqlsh` (preferred) or `mysql` (fallback).
Credentials come from env vars, never from the command line.

```bash
source scripts/tidbcloud-auth.sh
load_tidbcloud_auth --sut tidbx

mysqlsh --sql \
  --host "${TIDBCLOUD_DB_HOST:-}" \
  --port "${TIDBCLOUD_DB_PORT:-4000}" \
  --user "${TIDBCLOUD_DB_USER:-root}" \
  --passwords-from-stdin \
  --execute "SELECT 1;" <<< "${TIDBCLOUD_ROOT_PASSWORD:-}"
```

## Setup

Required env vars (set in `.env` or shell):
- `TIDB_PUBLIC_KEY` / `TIDB_PRIVATE_KEY` - API authentication
- `TIDBCLOUD_PROJECT_ID` - Target project

Optional: `TIDBCLOUD_HOST`, `TIDBCLOUD_BASE_PATH`, `TIDBCLOUD_REGION_NAME`,
`TIDBCLOUD_ROOT_PASSWORD`, `TIDBCLOUD_SKILL_DIR`

Premium-specific: `TIDBCLOUD_PREMIUM_HOST`, `TIDBCLOUD_PREMIUM_BASE_PATH`,
`TIDBCLOUD_PREMIUM_REGION_ID`

See `references/credentials.md` for detailed setup instructions.
Copy `.env.example` to `.env` and fill in your values.

## Troubleshooting

| Issue | Cause | Solution |
|-------|-------|----------|
| 401 Unauthorized | Bad credentials | Check TIDB_PUBLIC_KEY / TIDB_PRIVATE_KEY |
| Script not found | Wrong working directory | Run from skill root or set TIDBCLOUD_SKILL_DIR |
| Permission denied | Scripts not executable | `chmod +x scripts/*.sh` |
| jq not found | Missing dependency | Install jq: `brew install jq` or `apt install jq` |
| Empty response | Wrong SUT for tier | Check --sut flag matches cluster tier |
| 400 "CMEK is only supported for AWS cloud provider with Premium service plan" | Missing `awsPrincipal` in CMEK block | Add `"awsPrincipal":{"accountId":"<id>"}` from GET `/cmeks:principal` -- the swagger spec incorrectly marks this as readOnly/optional but the server requires it |

## Examples

### Example 1: Create a Starter cluster

User says: "Create a tidbx cluster named test-cluster"

Actions:
1. Use fast path: Starter create (no autoScaling)
2. Execute POST /clusters with displayName "test-cluster"
3. Poll until ACTIVE
4. Report cluster ID and connection info

### Example 2: List Premium clusters

User says: "Show me my premium tidb clusters"

Actions:
1. Detect "premium" -> use `--sut tidbx-premium`
2. Execute GET /tidbs?servicePlan=Premium
3. Display formatted list with names, IDs, states

### Example 3: Explore an unfamiliar API

User says: "How do I reset the root password on my cluster?"

Actions:
1. Use OpenAPI selector: `list --sut tidbx --query "password"`
2. Find relevant operationId
3. Extract the operation spec
4. Build and execute the request

### Example 4: Create a Premium cluster with CMEK

User says: "Create a premium cluster with my KMS key arn:aws:kms:us-east-1:123456:key/mrk-abc"

Actions:
1. Get principal: `GET /cmeks:principal?servicePlan=Premium&regionId=aws-us-east-1`
2. Extract `accountId` from response (e.g. `886436925895`)
3. Use CMEK fast path with both `awsKms.kmsKeyArn` AND `awsPrincipal.accountId`
4. Poll until ACTIVE
