@clawhub-jolestar-21112cba96
Operate DefiLlama public price APIs through UXC with a curated OpenAPI schema and read-first guardrails.
---
name: defillama-prices-openapi-skill
description: Operate DefiLlama public price APIs through UXC with a curated OpenAPI schema and read-first guardrails.
---
# DefiLlama Prices API Skill
Use this skill to run DefiLlama public price API operations through `uxc` + OpenAPI.
Reuse the `uxc` skill for shared execution, auth, and error-handling guidance.
## Prerequisites
- `uxc` is installed and available in `PATH`.
- Network access to `https://coins.llama.fi`.
- Access to the curated OpenAPI schema URL:
- `https://raw.githubusercontent.com/holon-run/uxc/main/skills/defillama-prices-openapi-skill/references/defillama-prices.openapi.json`
## Scope
This skill covers a small public read-only price surface on `coins.llama.fi`:
- current price lookups for one or more assets
This skill does **not** cover:
- write operations
- protocol or chain overview endpoints from `api.llama.fi`
- yield endpoints from `yields.llama.fi`
- DefiLlama Pro APIs
## Authentication
This public skill does not require authentication.
## Core Workflow
1. Use the fixed link command by default:
- `command -v defillama-prices-openapi-cli`
- If missing, create it:
`uxc link defillama-prices-openapi-cli https://coins.llama.fi --schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/defillama-prices-openapi-skill/references/defillama-prices.openapi.json`
- `defillama-prices-openapi-cli -h`
2. Inspect operation schema first:
- `defillama-prices-openapi-cli get:/prices/current/{coins} -h`
3. Prefer narrow read validation before broader reads:
- `defillama-prices-openapi-cli get:/prices/current/{coins} coins=coingecko:bitcoin searchWidth=4h`
## Operations
- `get:/prices/current/{coins}`
## Guardrails
- Keep automation on the JSON output envelope; do not use `--text`.
- Parse stable fields first: `ok`, `kind`, `protocol`, `data`, `error`.
- Treat this v1 skill as read-only.
- This skill only wraps `coins.llama.fi`; use the separate public analytics or yields skills for other DefiLlama hosts.
- `defillama-prices-openapi-cli <operation> ...` is equivalent to `uxc https://coins.llama.fi --schema-url <defillama_prices_openapi_schema> <operation> ...`.
## References
- Usage patterns: `references/usage-patterns.md`
- Curated OpenAPI schema: `references/defillama-prices.openapi.json`
- DefiLlama API docs: https://defillama.com/docs/api
FILE:agents/openai.yaml
interface:
display_name: "DefiLlama Prices API"
short_description: "Operate DefiLlama public asset price reads via UXC"
default_prompt: "Use $defillama-prices-openapi-skill to discover and execute DefiLlama public price operations through UXC with read-first guardrails."
FILE:references/defillama-prices.openapi.json
{
"openapi": "3.0.3",
"info": {
"title": "DefiLlama Prices Curated API",
"version": "1.0.0",
"description": "Curated read-only DefiLlama public price surface for UXC."
},
"servers": [
{
"url": "https://coins.llama.fi"
}
],
"paths": {
"/prices/current/{coins}": {
"get": {
"operationId": "getCurrentPrices",
"summary": "Get current prices for one or more assets",
"parameters": [
{
"name": "coins",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Comma-separated asset identifiers such as chain:address or coingecko:bitcoin."
},
{
"name": "searchWidth",
"in": "query",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Current prices response",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
}
}
}
FILE:references/usage-patterns.md
# DefiLlama Prices API Skill - Usage Patterns
## Link Setup
```bash
command -v defillama-prices-openapi-cli
uxc link defillama-prices-openapi-cli https://coins.llama.fi \
--schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/defillama-prices-openapi-skill/references/defillama-prices.openapi.json
defillama-prices-openapi-cli -h
```
This public skill does not require auth.
## Read Examples
```bash
# Read a current price for one asset
defillama-prices-openapi-cli get:/prices/current/{coins} \
coins=coingecko:bitcoin \
searchWidth=4h
# Read multiple assets at once
defillama-prices-openapi-cli get:/prices/current/{coins} \
coins=coingecko:bitcoin,ethereum:0x0000000000000000000000000000000000000000 \
searchWidth=4h
```
## Fallback Equivalence
- `defillama-prices-openapi-cli <operation> ...` is equivalent to
`uxc https://coins.llama.fi --schema-url <defillama_prices_openapi_schema> <operation> ...`.
FILE:scripts/validate.sh
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "BASH_SOURCE[0]")/../../.." && pwd)"
SKILL_DIR="ROOT_DIR/skills/defillama-prices-openapi-skill"
SKILL_FILE="SKILL_DIR/SKILL.md"
OPENAI_FILE="SKILL_DIR/agents/openai.yaml"
USAGE_FILE="SKILL_DIR/references/usage-patterns.md"
SCHEMA_FILE="SKILL_DIR/references/defillama-prices.openapi.json"
fail() {
printf '[validate] error: %s\n' "$*" >&2
exit 1
}
need_cmd() {
command -v "$1" >/dev/null 2>&1 || fail "required command not found: $1"
}
need_cmd jq
need_cmd rg
for file in "SKILL_FILE" "OPENAI_FILE" "USAGE_FILE" "SCHEMA_FILE"; do
[[ -f "file" ]] || fail "missing required file: file"
done
jq -e '.openapi and .paths["/prices/current/{coins}"]' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'OpenAPI schema missing expected DefiLlama price path'
rg -q '^name:\s*defillama-prices-openapi-skill\s*$' "SKILL_FILE" || fail 'invalid skill name'
rg -q 'command -v defillama-prices-openapi-cli' "SKILL_FILE" || fail 'missing link-first command check'
rg -q 'uxc link defillama-prices-openapi-cli https://coins.llama.fi --schema-url ' "SKILL_FILE" || fail 'missing fixed link create command'
rg -q 'defillama-prices-openapi-cli get:/prices/current/\{coins\} -h' "SKILL_FILE" || fail 'missing operation help example'
rg -q 'does not require auth' "USAGE_FILE" || fail 'missing no-auth guidance'
if rg -q -- "--args\\s+'\\{" "SKILL_FILE" "USAGE_FILE"; then
fail 'found banned legacy JSON argument pattern'
fi
rg -q '^\s*display_name:\s*"DefiLlama Prices API"\s*$' "OPENAI_FILE" || fail 'missing display_name'
rg -q '^\s*default_prompt:\s*".*\$defillama-prices-openapi-skill.*"\s*$' "OPENAI_FILE" || fail 'default_prompt must mention $defillama-prices-openapi-skill'
echo "skills/defillama-prices-openapi-skill validation passed"
Use the LI.FI MCP server through UXC for cross-chain route discovery, bridge/DEX availability checks, token and chain lookup, gas/balance/allowance checks, q...
---
name: lifi-mcp-skill
description: Use the LI.FI MCP server through UXC for cross-chain route discovery, bridge/DEX availability checks, token and chain lookup, gas/balance/allowance checks, quote generation, and transfer status tracking. Use when tasks involve planning or monitoring cross-chain swaps and bridges without signing or broadcasting transactions.
---
# LI.FI MCP Skill
Use this skill to run LI.FI MCP operations through `uxc`.
Reuse the `uxc` skill for generic protocol discovery, auth binding, envelope parsing, and error handling.
## Prerequisites
- `uxc` is installed and available in `PATH`.
- Network access to `https://mcp.li.quest/mcp`.
- Optional: a LI.FI API key for higher rate limits.
## Core Workflow
1. Verify endpoint and protocol with help-first probing:
- `uxc https://mcp.li.quest/mcp -h`
- Confirm protocol is MCP (`protocol == "mcp"` in the envelope).
2. Optional auth setup for higher rate limits:
- `uxc auth credential set lifi-mcp --auth-type bearer --secret-env LIFI_API_KEY`
- `uxc auth binding add --id lifi-mcp --host mcp.li.quest --path-prefix /mcp --scheme https --credential lifi-mcp --priority 100`
- LI.FI accepts either `Authorization: Bearer <key>` or `X-LiFi-Api-Key`; prefer bearer unless endpoint behavior changes.
3. Use a fixed link command by default:
- `command -v lifi-mcp-cli`
- If missing, create it:
- `uxc link lifi-mcp-cli https://mcp.li.quest/mcp`
- `lifi-mcp-cli -h`
4. Inspect operation schema before execution:
- `lifi-mcp-cli get-chains -h`
- `lifi-mcp-cli get-token -h`
- `lifi-mcp-cli get-quote -h`
- `lifi-mcp-cli get-status -h`
5. Prefer discovery first, then route/quote, then execution-precheck queries.
## Capability Map
- Chain and token discovery:
- `get-chains`
- `get-chain-by-id`
- `get-chain-by-name`
- `get-tokens`
- `get-token`
- Route discovery and provider availability:
- `get-connections`
- `get-tools`
- Quotes and route planning:
- `get-quote`
- `get-routes`
- `get-step-transaction`
- `get-quote-with-calls`
- Wallet prechecks:
- `get-native-token-balance`
- `get-token-balance`
- `get-allowance`
- `get-gas-prices`
- `get-gas-suggestion`
- Monitoring and service checks:
- `get-status`
- `test-api-key`
- `health-check`
Always inspect host help and operation help in the current endpoint version before relying on an operation name or argument shape.
## Recommended Usage Pattern
1. Discover chain IDs dynamically:
- `lifi-mcp-cli get-chains`
- `lifi-mcp-cli get-chain-by-name name=base`
2. Resolve token addresses before quoting:
- `lifi-mcp-cli get-token chain=8453 token=USDC`
3. Check whether a route exists before asking for a quote:
- `lifi-mcp-cli get-connections fromChain=8453 toChain=42161`
4. Generate the quote:
- `lifi-mcp-cli get-quote fromChain=8453 toChain=42161 fromToken=USDC toToken=USDC fromAddress=<wallet> fromAmount=<smallest-unit-amount>`
5. Validate execution preconditions:
- `lifi-mcp-cli get-allowance ...`
- `lifi-mcp-cli get-native-token-balance ...`
6. Use `get-status` only after the externally signed transaction has been broadcast.
## Guardrails
- Keep automation on JSON output envelope; do not rely on `--text`.
- Parse stable fields first: `ok`, `kind`, `protocol`, `data`, `error`.
- Use `lifi-mcp-cli` as the default command path.
- `lifi-mcp-cli <operation> ...` is equivalent to `uxc https://mcp.li.quest/mcp <operation> ...` when the same auth binding is configured.
- Use direct `uxc "<endpoint>" ...` only as a temporary fallback when link setup is unavailable.
- Prefer `key=value` for simple arguments and positional JSON for nested objects.
- This endpoint is read-only from the agent perspective:
- it does **not** sign transactions
- it does **not** broadcast transactions
- it returns unsigned `transactionRequest` objects for external wallet execution
- Do not present `get-quote` or `get-step-transaction` as executed trades; they are execution plans only.
- Before suggesting an ERC20 route as ready to execute, check allowance if the route needs approval.
- Prefer `get-routes` only when the user explicitly wants multiple alternatives; default to `get-quote` for the best route.
- In live testing, chain lookup tools accepted names, but token/balance/allowance tools were more reliable with numeric chain IDs. Prefer numeric IDs after discovery.
## Tested Real Scenario
The endpoint was verified through `uxc` host discovery and returned a live MCP tool list including:
- `get-allowance`
- `get-chain-by-id`
- `get-chain-by-name`
- `get-chains`
- `get-connections`
- `get-gas-prices`
- `get-gas-suggestion`
- `get-quote`
- `get-routes`
- `get-status`
- `get-token`
- `get-tokens`
- `get-tools`
- `health-check`
This confirms the skill target is a real hosted MCP surface accessible via UXC.
## References
- Invocation patterns:
- `references/usage-patterns.md`
FILE:agents/openai.yaml
interface:
display_name: "LI.FI MCP"
short_description: "Cross-chain discovery, quote, allowance, gas, and status via LI.FI MCP"
default_prompt: "Use $lifi-mcp-skill to run LI.FI MCP workflows for cross-chain route discovery, token and chain lookup, quote generation, balance/allowance/gas checks, and transfer status tracking without signing or broadcasting transactions."
FILE:references/usage-patterns.md
# LI.FI MCP Usage Patterns
Use these patterns after the host and optional auth binding are working.
## 1. Basic endpoint discovery
```bash
uxc https://mcp.li.quest/mcp -h
lifi-mcp-cli -h
```
Inspect one operation before use:
```bash
lifi-mcp-cli get-quote -h
```
## 2. Chain and token resolution
Resolve chain names and IDs dynamically instead of hardcoding them:
```bash
lifi-mcp-cli get-chain-by-name name=base
lifi-mcp-cli get-chain-by-id id=42161
lifi-mcp-cli get-chains chainTypes=EVM
```
Resolve token metadata before building a quote:
```bash
lifi-mcp-cli get-token chain=8453 token=USDC
lifi-mcp-cli get-tokens chains=8453,42161
```
## 3. Route existence check
Use this when the user asks whether a route is available:
```bash
lifi-mcp-cli get-connections fromChain=8453 toChain=42161
```
Narrow by bridge or token only when the user cares about a specific route family.
## 4. Best-route quote
Use `get-quote` for the default path when the user wants the best executable route:
```bash
lifi-mcp-cli get-quote \
fromChain=8453 \
toChain=42161 \
fromToken=USDC \
toToken=USDC \
fromAddress=0xYourWallet \
fromAmount=1000000
```
Notes:
- Chain discovery helpers accept names such as `base`, but live tool execution was more reliable with numeric chain IDs such as `8453`.
- `fromAmount` is in the token's smallest unit.
- `toAddress` is optional and defaults to `fromAddress`.
- The response contains an unsigned `transactionRequest` object.
## 5. Multiple-route comparison
Use this only when the user explicitly wants alternatives:
```bash
lifi-mcp-cli get-routes \
fromChainId=8453 \
toChainId=42161 \
fromTokenAddress=0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 \
toTokenAddress=0xaf88d065e77c8cC2239327C5EDb3A432268e5831 \
fromAddress=0xYourWallet \
fromAmount=1000000
```
Then inspect a single chosen step:
```bash
lifi-mcp-cli get-step-transaction '<step-json>'
```
## 6. Pre-execution checks
Check native gas balance:
```bash
lifi-mcp-cli get-native-token-balance chain=8453 address=0xYourWallet
```
Check ERC20 balance:
```bash
lifi-mcp-cli get-token-balance \
chain=8453 \
tokenAddress=0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 \
walletAddress=0xYourWallet
```
Check allowance using the approval address from a quote:
```bash
lifi-mcp-cli get-allowance \
chain=8453 \
tokenAddress=0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 \
ownerAddress=0xYourWallet \
spenderAddress=0xApprovalAddress
```
## 7. Gas and status monitoring
Get general gas data:
```bash
lifi-mcp-cli get-gas-prices
lifi-mcp-cli get-gas-suggestion chainId=8453
```
Track an already submitted cross-chain transaction:
```bash
lifi-mcp-cli get-status txHash=0x...
```
## 8. Auth and health checks
Validate the optional API key setup:
```bash
lifi-mcp-cli test-api-key
```
Check service health:
```bash
lifi-mcp-cli health-check
```
FILE:scripts/validate.sh
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "BASH_SOURCE[0]")/../../.." && pwd)"
SKILL_DIR="ROOT_DIR/skills/lifi-mcp-skill"
SKILL_FILE="SKILL_DIR/SKILL.md"
OPENAI_FILE="SKILL_DIR/agents/openai.yaml"
fail() {
printf '[validate] error: %s\n' "$*" >&2
exit 1
}
need_cmd() {
command -v "$1" >/dev/null 2>&1 || fail "required command not found: $1"
}
need_cmd rg
required_files=(
"SKILL_FILE"
"OPENAI_FILE"
"SKILL_DIR/references/usage-patterns.md"
)
for file in "required_files[@]"; do
[[ -f "file" ]] || fail "missing required file: file"
done
head -n 1 "SKILL_FILE" | rg -q '^---$' || fail 'SKILL.md must include YAML frontmatter'
tail -n +2 "SKILL_FILE" | rg -q '^---$' || fail 'SKILL.md must include YAML frontmatter'
rg -q '^name:\s*lifi-mcp-skill\s*$' "SKILL_FILE" || fail 'SKILL.md frontmatter must define: name: lifi-mcp-skill'
rg -q '^description:\s*.+' "SKILL_FILE" || fail 'SKILL.md frontmatter must define a description'
rg -q 'https://mcp.li.quest/mcp' "SKILL_FILE" || fail 'SKILL.md must document MCP endpoint'
rg -q 'command -v lifi-mcp-cli' "SKILL_FILE" || fail 'SKILL.md must include link command existence check'
rg -q 'uxc link lifi-mcp-cli https://mcp.li.quest/mcp' "SKILL_FILE" || fail 'SKILL.md must include fixed link creation command'
rg -q 'lifi-mcp-cli -h' "SKILL_FILE" "SKILL_DIR/references/usage-patterns.md" || fail 'LI.FI docs must use lifi-mcp-cli help-first discovery'
rg -q 'get-quote' "SKILL_FILE" || fail 'SKILL.md must document get-quote tool'
rg -q 'references/usage-patterns.md' "SKILL_FILE" || fail 'SKILL.md must reference usage-patterns.md'
rg -q 'equivalent to `uxc https://mcp.li.quest/mcp <operation> ...`' "SKILL_FILE" "SKILL_DIR/references/usage-patterns.md" || fail 'LI.FI docs must document fallback equivalence guidance'
if rg -q -- '--input-json|lifi-mcp-cli list|lifi-mcp-cli describe|lifi-mcp-cli call' "SKILL_FILE" "SKILL_DIR/references/usage-patterns.md"; then
fail 'LI.FI docs must not use list/describe/call/--input-json in default examples'
fi
if rg -q -- "--args '\\{" "SKILL_FILE" "SKILL_DIR/references/usage-patterns.md"; then
fail 'LI.FI docs must not pass raw JSON via --args'
fi
rg -q '^\s*display_name:\s*"LI\.FI MCP"\s*$' "OPENAI_FILE" || fail 'agents/openai.yaml must define interface.display_name'
rg -q '^\s*short_description:\s*".+"\s*$' "OPENAI_FILE" || fail 'agents/openai.yaml must define interface.short_description'
rg -q '^\s*default_prompt:\s*".*\$lifi-mcp-skill.*"\s*$' "OPENAI_FILE" || fail 'agents/openai.yaml default_prompt must mention $lifi-mcp-skill'
echo 'skills/lifi-mcp-skill validation passed'
Use CoinMarketCap MCP through UXC for crypto market quotes, technical analysis, on-chain metrics, global market overview, narratives, macro events, news, and...
---
name: coinmarketcap-mcp-skill
description: Use CoinMarketCap MCP through UXC for crypto market quotes, technical analysis, on-chain metrics, global market overview, narratives, macro events, news, and semantic search with help-first schema inspection and API-key auth.
---
# CoinMarketCap MCP Skill
Use this skill to run CoinMarketCap MCP operations through `uxc`.
Reuse the `uxc` skill for shared protocol discovery, output parsing, and generic auth/binding flows.
## Prerequisites
- `uxc` is installed and available in `PATH`.
- Network access to `https://mcp.coinmarketcap.com/mcp`.
- A CoinMarketCap MCP API key is available.
## Core Workflow
1. Confirm endpoint and protocol with help-first probing:
- `uxc https://mcp.coinmarketcap.com/mcp -h`
- expected unauthenticated behavior today: `401 Unauthorized` with `Token not found`
2. Configure credential/binding for repeatable auth:
- `uxc auth credential set coinmarketcap-mcp --auth-type api_key --header "X-CMC-MCP-API-KEY={{secret}}" --secret-env COINMARKETCAP_MCP_API_KEY`
- `uxc auth credential set coinmarketcap-mcp --auth-type api_key --header "X-CMC-MCP-API-KEY={{secret}}" --secret-op op://Engineering/coinmarketcap/mcp-api-key`
- `uxc auth binding add --id coinmarketcap-mcp --host mcp.coinmarketcap.com --path-prefix /mcp --scheme https --credential coinmarketcap-mcp --priority 100`
3. Use fixed link command by default:
- `command -v coinmarketcap-mcp-cli`
- If missing, create it: `uxc link coinmarketcap-mcp-cli https://mcp.coinmarketcap.com/mcp`
- `coinmarketcap-mcp-cli -h`
4. Inspect operation schema before execution:
- `coinmarketcap-mcp-cli get_crypto_quotes_latest -h`
- `coinmarketcap-mcp-cli get_global_metrics_latest -h`
- `coinmarketcap-mcp-cli trending_crypto_narratives -h`
- `coinmarketcap-mcp-cli get_crypto_latest_news -h`
5. Prefer read-only discovery first, then expand into higher-cost or plan-gated endpoints.
## Capability Map
- Market data and discovery:
- `get_crypto_quotes_latest`
- `search_cryptos`
- `get_crypto_info`
- Technical analysis:
- `get_crypto_technical_analysis`
- `get_crypto_marketcap_technical_analysis`
- On-chain and macro metrics:
- `get_crypto_metrics`
- `get_global_metrics_latest`
- `get_global_crypto_derivatives_metrics`
- `get_upcoming_macro_events`
- Themes, news, and search:
- `trending_crypto_narratives`
- `get_crypto_latest_news`
- `search_crypto_info`
Inspect `coinmarketcap-mcp-cli -h` after auth setup for the current full tool list. CoinMarketCap can revise or expand its MCP tool surface independently of this wrapper skill.
## Recommended Usage Pattern
1. Start with one focused read goal:
- current quote and market cap for a coin
- trend or narrative scan for a sector
- global market and derivatives snapshot
- latest news or semantic lookup on a project/topic
2. Run `-h` on the specific tool before the first real call.
3. Prefer id-, slug-, or keyword-scoped reads before broad market sweeps.
4. Parse the JSON envelope first, then inspect `data`.
## Guardrails
- Keep automation on JSON output envelope; do not rely on `--text`.
- Parse stable fields first: `ok`, `kind`, `protocol`, `data`, `error`.
- Use `coinmarketcap-mcp-cli` as default command path.
- `coinmarketcap-mcp-cli <operation> ...` is equivalent to `uxc https://mcp.coinmarketcap.com/mcp <operation> ...`.
- If unauthenticated probe or runtime call returns `401 Unauthorized` or `Token not found`:
- confirm auth binding matches endpoint with `uxc auth binding match https://mcp.coinmarketcap.com/mcp`
- confirm credential shape with `uxc auth credential info coinmarketcap-mcp`
- reset credential as API-key header if needed: `uxc auth credential set coinmarketcap-mcp --auth-type api_key --header "X-CMC-MCP-API-KEY={{secret}}" --secret-env COINMARKETCAP_MCP_API_KEY`
- CoinMarketCap documents an x402 pay-per-call path, but `uxc` does not implement x402 payment handling today. This skill documents only the API-key route.
- Higher CoinMarketCap plans unlock additional datasets or request rates. If a tool returns a plan or quota error, verify the current account tier before retrying.
- CoinMarketCap MCP is read-only. Do not present it as a trading or order-routing integration.
- Use `key=value` only for simple scalar inputs.
- Prefer positional JSON when an operation accepts nested objects, arrays, or optional filters that may evolve.
- Do not assume tool argument names from memory; inspect `<operation> -h` first because CoinMarketCap may revise MCP schemas independently of this skill.
## References
- Invocation patterns:
- `references/usage-patterns.md`
FILE:agents/openai.yaml
interface:
display_name: "CoinMarketCap MCP"
short_description: "Crypto quotes, metrics, narratives, and news via CoinMarketCap MCP"
default_prompt: "Use $coinmarketcap-mcp-skill to query CoinMarketCap MCP for crypto market quotes, technical analysis, on-chain metrics, global market overview, narratives, macro events, news, and semantic search with help-first inspection and API-key auth."
FILE:references/usage-patterns.md
# Usage Patterns
This skill defaults to fixed link command `coinmarketcap-mcp-cli`.
## Setup
```bash
command -v coinmarketcap-mcp-cli
uxc link coinmarketcap-mcp-cli https://mcp.coinmarketcap.com/mcp
coinmarketcap-mcp-cli -h
```
Auth setup:
```bash
uxc auth credential set coinmarketcap-mcp --auth-type api_key --header "X-CMC-MCP-API-KEY={{secret}}" --secret-env COINMARKETCAP_MCP_API_KEY
uxc auth binding add --id coinmarketcap-mcp --host mcp.coinmarketcap.com --path-prefix /mcp --scheme https --credential coinmarketcap-mcp --priority 100
```
Optional secret manager source:
```bash
uxc auth credential set coinmarketcap-mcp --auth-type api_key --header "X-CMC-MCP-API-KEY={{secret}}" --secret-op op://Engineering/coinmarketcap/mcp-api-key
```
## Help-First Discovery
```bash
coinmarketcap-mcp-cli get_crypto_quotes_latest -h
coinmarketcap-mcp-cli get_crypto_info -h
coinmarketcap-mcp-cli get_global_metrics_latest -h
coinmarketcap-mcp-cli trending_crypto_narratives -h
coinmarketcap-mcp-cli get_crypto_latest_news -h
```
## Quotes And Metadata
Get the latest quote for BTC:
```bash
coinmarketcap-mcp-cli get_crypto_quotes_latest id=1
```
Search for projects by keyword:
```bash
coinmarketcap-mcp-cli search_cryptos query='liquid staking' limit=5
```
Fetch coin metadata with positional JSON:
```bash
coinmarketcap-mcp-cli get_crypto_info '{"symbol":"ETH","aux":["urls","logo","description","tags"]}'
```
## Technical Analysis And Metrics
Inspect technical analysis options first:
```bash
coinmarketcap-mcp-cli get_crypto_technical_analysis -h
coinmarketcap-mcp-cli get_crypto_marketcap_technical_analysis -h
```
Inspect crypto metrics:
```bash
coinmarketcap-mcp-cli get_crypto_metrics -h
```
## Global Market And Narratives
Fetch global market metrics:
```bash
coinmarketcap-mcp-cli get_global_metrics_latest
```
Inspect derivatives and narrative tools:
```bash
coinmarketcap-mcp-cli get_global_crypto_derivatives_metrics -h
coinmarketcap-mcp-cli trending_crypto_narratives -h
coinmarketcap-mcp-cli get_upcoming_macro_events -h
```
## News And Semantic Search
Inspect latest news tool:
```bash
coinmarketcap-mcp-cli get_crypto_latest_news -h
```
Search crypto concepts or documentation:
```bash
coinmarketcap-mcp-cli search_crypto_info query='restaking market map' limit=5
```
## Practical Rules
- Start with quotes, metadata, or global metrics before using broader search tools.
- Keep keyword searches short and specific.
- Use positional JSON when the tool accepts arrays or nested filters.
- If a tool fails with an auth, quota, or plan error, verify the stored key and current CoinMarketCap tier.
- CoinMarketCap MCP is read-only and does not support trading.
- CoinMarketCap documents an x402 pay-per-call option, but this skill does not use it because `uxc` does not implement x402 payment handling today.
## Fallback Equivalence
- `coinmarketcap-mcp-cli <operation> ...` is equivalent to `uxc https://mcp.coinmarketcap.com/mcp <operation> ...`.
FILE:scripts/validate.sh
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "BASH_SOURCE[0]")/../../.." && pwd)"
SKILL_DIR="ROOT_DIR/skills/coinmarketcap-mcp-skill"
SKILL_FILE="SKILL_DIR/SKILL.md"
OPENAI_FILE="SKILL_DIR/agents/openai.yaml"
fail() {
printf '[validate] error: %s\n' "$*" >&2
exit 1
}
need_cmd() {
command -v "$1" >/dev/null 2>&1 || fail "required command not found: $1"
}
need_cmd rg
required_files=(
"SKILL_FILE"
"OPENAI_FILE"
"SKILL_DIR/references/usage-patterns.md"
"SKILL_DIR/scripts/validate.sh"
)
for file in "required_files[@]"; do
[[ -f "file" ]] || fail "missing required file: file"
done
if ! head -n 1 "SKILL_FILE" | rg -q '^---$'; then
fail "SKILL.md must include YAML frontmatter"
fi
if ! tail -n +2 "SKILL_FILE" | rg -q '^---$'; then
fail "SKILL.md must include YAML frontmatter"
fi
if ! rg -q '^name:\s*coinmarketcap-mcp-skill\s*$' "SKILL_FILE"; then
fail "SKILL.md frontmatter must define: name: coinmarketcap-mcp-skill"
fi
if ! rg -q '^description:\s*.+' "SKILL_FILE"; then
fail "SKILL.md frontmatter must define a description"
fi
if ! rg -q 'mcp\.coinmarketcap\.com/mcp' "SKILL_FILE"; then
fail "SKILL.md must document CoinMarketCap MCP endpoint"
fi
if ! rg -q 'X-CMC-MCP-API-KEY' "SKILL_FILE" "SKILL_DIR/references/usage-patterns.md"; then
fail "CoinMarketCap docs must configure X-CMC-MCP-API-KEY auth"
fi
if ! rg -q 'command -v coinmarketcap-mcp-cli' "SKILL_FILE"; then
fail "SKILL.md must include link command existence check"
fi
if ! rg -q 'uxc link coinmarketcap-mcp-cli https://mcp\.coinmarketcap\.com/mcp' "SKILL_FILE" "SKILL_DIR/references/usage-patterns.md"; then
fail "docs must include fixed link creation command"
fi
if ! rg -q 'coinmarketcap-mcp-cli -h' "SKILL_FILE" "SKILL_DIR/references/usage-patterns.md"; then
fail "docs must use coinmarketcap-mcp-cli help-first discovery"
fi
for op in get_crypto_quotes_latest get_global_metrics_latest trending_crypto_narratives get_crypto_latest_news; do
if ! rg -q "op" "SKILL_FILE" "SKILL_DIR/references/usage-patterns.md"; then
fail "CoinMarketCap docs must include op"
fi
done
if ! rg -q 'search_cryptos|search_crypto_info' "SKILL_FILE" "SKILL_DIR/references/usage-patterns.md"; then
fail "CoinMarketCap docs must include search tool coverage"
fi
if rg -q -- '--input-json|coinmarketcap-mcp-cli list|coinmarketcap-mcp-cli describe|coinmarketcap-mcp-cli call' "SKILL_FILE" "SKILL_DIR/references/usage-patterns.md"; then
fail "CoinMarketCap docs must not use list/describe/call/--input-json in default examples"
fi
if ! rg -q 'x402' "SKILL_FILE" "SKILL_DIR/references/usage-patterns.md"; then
fail "CoinMarketCap docs must explain current x402 scope boundary"
fi
if ! rg -q 'equivalent to `uxc https://mcp\.coinmarketcap\.com/mcp' "SKILL_FILE" "SKILL_DIR/references/usage-patterns.md"; then
fail "CoinMarketCap docs must include single-point fallback equivalence guidance"
fi
if ! rg -q '^\s*display_name:\s*"CoinMarketCap MCP"\s*$' "OPENAI_FILE"; then
fail "agents/openai.yaml must define interface.display_name"
fi
if ! rg -q '^\s*short_description:\s*".+"\s*$' "OPENAI_FILE"; then
fail "agents/openai.yaml must define interface.short_description"
fi
if ! rg -q '^\s*default_prompt:\s*".*\$coinmarketcap-mcp-skill.*"\s*$' "OPENAI_FILE"; then
fail 'agents/openai.yaml default_prompt must mention $coinmarketcap-mcp-skill'
fi
echo "skills/coinmarketcap-mcp-skill validation passed"
Use Birdeye MCP through UXC for token market data, trending and discovery workflows, price monitoring, and DEX-related reads with help-first live tool discov...
---
name: birdeye-mcp-skill
description: Use Birdeye MCP through UXC for token market data, trending and discovery workflows, price monitoring, and DEX-related reads with help-first live tool discovery and API-key auth.
---
# Birdeye MCP Skill
Use this skill to run Birdeye MCP operations through `uxc`.
Reuse the `uxc` skill for shared protocol discovery, output parsing, and generic auth/binding flows.
## Prerequisites
- `uxc` is installed and available in `PATH`.
- Network access to `https://mcp.birdeye.so/mcp`.
- A Birdeye API key is available.
## Core Workflow
1. Confirm endpoint and protocol with help-first probing:
- `uxc https://mcp.birdeye.so/mcp -h`
- expected unauthenticated behavior today: `401 Unauthorized`
2. Configure credential/binding for repeatable auth:
- `uxc auth credential set birdeye-mcp --auth-type api_key --header "X-API-KEY={{secret}}" --secret-env BIRDEYE_API_KEY`
- `uxc auth credential set birdeye-mcp --auth-type api_key --header "X-API-KEY={{secret}}" --secret-op op://Engineering/birdeye/api-key`
- `uxc auth binding add --id birdeye-mcp --host mcp.birdeye.so --path-prefix /mcp --scheme https --credential birdeye-mcp --priority 100`
3. Use fixed link command by default:
- `command -v birdeye-mcp-cli`
- If missing, create it: `uxc link birdeye-mcp-cli https://mcp.birdeye.so/mcp`
- `birdeye-mcp-cli -h`
4. Inspect the live tool list before execution:
- `birdeye-mcp-cli -h`
- then inspect the specific operation you need with `<operation> -h`
5. Prefer read-only discovery first, then broader monitoring queries.
## Capability Focus
Birdeye MCP is a fit for these read-heavy workflows:
- token market data
- trending or discovery views
- price monitoring
- DEX liquidity or trading context
- token or pair lookup
Inspect `birdeye-mcp-cli -h` after auth setup for the current tool list. Birdeye MCP is still in beta and the live tool surface may evolve independently of this wrapper skill.
## Recommended Usage Pattern
1. Start from one focused read goal:
- current market data for a token
- trending token or narrative discovery
- DEX liquidity or price movement checks
2. Run host help first, then operation help.
3. Prefer narrow symbol, address, or chain scopes before broad scans.
4. Parse the JSON envelope first, then inspect `data`.
## Guardrails
- Keep automation on JSON output envelope; do not rely on `--text`.
- Parse stable fields first: `ok`, `kind`, `protocol`, `data`, `error`.
- Use `birdeye-mcp-cli` as default command path.
- `birdeye-mcp-cli <operation> ...` is equivalent to `uxc https://mcp.birdeye.so/mcp <operation> ...`.
- If unauthenticated probe or runtime call returns `401 Unauthorized`:
- confirm auth binding matches endpoint with `uxc auth binding match https://mcp.birdeye.so/mcp`
- confirm credential shape with `uxc auth credential info birdeye-mcp`
- reset credential as API-key header if needed: `uxc auth credential set birdeye-mcp --auth-type api_key --header "X-API-KEY={{secret}}" --secret-env BIRDEYE_API_KEY`
- Birdeye MCP is beta. Do not hardcode assumptions about the live tool list or argument names; inspect `-h` first.
- Keep initial queries small and specific because market/discovery tools can return wide datasets.
- Treat this skill as read-only market and discovery access, not a trading or execution surface.
## References
- Invocation patterns:
- `references/usage-patterns.md`
FILE:agents/openai.yaml
interface:
display_name: "Birdeye MCP"
short_description: "Token market, discovery, and DEX context via Birdeye MCP"
default_prompt: "Use $birdeye-mcp-skill to query Birdeye MCP for token market data, trending and discovery workflows, price monitoring, and DEX-related reads with help-first live tool discovery and API-key auth."
FILE:references/usage-patterns.md
# Usage Patterns
This skill defaults to fixed link command `birdeye-mcp-cli`.
## Setup
```bash
command -v birdeye-mcp-cli
uxc link birdeye-mcp-cli https://mcp.birdeye.so/mcp
birdeye-mcp-cli -h
```
Auth setup:
```bash
uxc auth credential set birdeye-mcp --auth-type api_key --header "X-API-KEY={{secret}}" --secret-env BIRDEYE_API_KEY
uxc auth binding add --id birdeye-mcp --host mcp.birdeye.so --path-prefix /mcp --scheme https --credential birdeye-mcp --priority 100
```
Optional secret manager source:
```bash
uxc auth credential set birdeye-mcp --auth-type api_key --header "X-API-KEY={{secret}}" --secret-op op://Engineering/birdeye/api-key
```
## Help-First Discovery
```bash
birdeye-mcp-cli -h
```
Then inspect the concrete operation you want from the live tool list:
```bash
birdeye-mcp-cli <operation> -h
```
## Practical Rules
- Start with host help because Birdeye MCP is beta and the tool list can evolve.
- After picking the relevant operation, inspect `<operation> -h` before the first real call.
- Keep scopes narrow: one token, one pair, one chain, or one market slice at a time.
- Birdeye MCP is a read-only market/discovery surface; do not treat it as trading execution.
- If a probe returns `401 Unauthorized`, confirm the `X-API-KEY` credential binding first.
## Fallback Equivalence
- `birdeye-mcp-cli <operation> ...` is equivalent to `uxc https://mcp.birdeye.so/mcp <operation> ...`.
FILE:scripts/validate.sh
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "BASH_SOURCE[0]")/../../.." && pwd)"
SKILL_DIR="ROOT_DIR/skills/birdeye-mcp-skill"
SKILL_FILE="SKILL_DIR/SKILL.md"
OPENAI_FILE="SKILL_DIR/agents/openai.yaml"
fail() {
printf '[validate] error: %s\n' "$*" >&2
exit 1
}
need_cmd() {
command -v "$1" >/dev/null 2>&1 || fail "required command not found: $1"
}
need_cmd rg
required_files=(
"SKILL_FILE"
"OPENAI_FILE"
"SKILL_DIR/references/usage-patterns.md"
"SKILL_DIR/scripts/validate.sh"
)
for file in "required_files[@]"; do
[[ -f "file" ]] || fail "missing required file: file"
done
if ! head -n 1 "SKILL_FILE" | rg -q '^---$'; then
fail "SKILL.md must include YAML frontmatter"
fi
if ! tail -n +2 "SKILL_FILE" | rg -q '^---$'; then
fail "SKILL.md must include YAML frontmatter"
fi
if ! rg -q '^name:\s*birdeye-mcp-skill\s*$' "SKILL_FILE"; then
fail "SKILL.md frontmatter must define: name: birdeye-mcp-skill"
fi
if ! rg -q '^description:\s*.+' "SKILL_FILE"; then
fail "SKILL.md frontmatter must define a description"
fi
if ! rg -q 'mcp\.birdeye\.so/mcp' "SKILL_FILE" "SKILL_DIR/references/usage-patterns.md"; then
fail "docs must document the Birdeye MCP endpoint"
fi
if ! rg -q 'X-API-KEY' "SKILL_FILE" "SKILL_DIR/references/usage-patterns.md"; then
fail "docs must configure X-API-KEY auth"
fi
if ! rg -q 'command -v birdeye-mcp-cli' "SKILL_FILE"; then
fail "SKILL.md must include link command existence check"
fi
if ! rg -q 'uxc link birdeye-mcp-cli https://mcp\.birdeye\.so/mcp' "SKILL_FILE" "SKILL_DIR/references/usage-patterns.md"; then
fail "docs must include fixed link creation command"
fi
if ! rg -q 'birdeye-mcp-cli -h' "SKILL_FILE" "SKILL_DIR/references/usage-patterns.md"; then
fail "docs must use birdeye-mcp-cli help-first discovery"
fi
if ! rg -q 'token market data|trending|price monitoring|DEX' "SKILL_FILE" "SKILL_DIR/references/usage-patterns.md"; then
fail "docs must describe Birdeye capability focus"
fi
if rg -q -- '--input-json|birdeye-mcp-cli list|birdeye-mcp-cli describe|birdeye-mcp-cli call' "SKILL_FILE" "SKILL_DIR/references/usage-patterns.md"; then
fail "Birdeye docs must not use list/describe/call/--input-json in default examples"
fi
if ! rg -q 'equivalent to `uxc https://mcp\.birdeye\.so/mcp' "SKILL_FILE" "SKILL_DIR/references/usage-patterns.md"; then
fail "Birdeye docs must include single-point fallback equivalence guidance"
fi
if ! rg -q '^\s*display_name:\s*"Birdeye MCP"\s*$' "OPENAI_FILE"; then
fail "agents/openai.yaml must define interface.display_name"
fi
if ! rg -q '^\s*short_description:\s*".+"\s*$' "OPENAI_FILE"; then
fail "agents/openai.yaml must define interface.short_description"
fi
if ! rg -q '^\s*default_prompt:\s*".*\$birdeye-mcp-skill.*"\s*$' "OPENAI_FILE"; then
fail 'agents/openai.yaml default_prompt must mention $birdeye-mcp-skill'
fi
echo "skills/birdeye-mcp-skill validation passed"
Operate Blockscout explorer reads through UXC with a curated OpenAPI schema, instance-specific host selection, and read-first guardrails.
---
name: blockscout-openapi-skill
description: Operate Blockscout explorer reads through UXC with a curated OpenAPI schema, instance-specific host selection, and read-first guardrails.
---
# Blockscout Explorer API Skill
Use this skill to run Blockscout explorer operations through `uxc` + OpenAPI.
Reuse the `uxc` skill for shared execution, auth, and error-handling guidance.
## Prerequisites
- `uxc` is installed and available in `PATH`.
- Network access to a Blockscout deployment that exposes `/api/v2`.
- Access to the curated OpenAPI schema URL:
- `https://raw.githubusercontent.com/holon-run/uxc/main/skills/blockscout-openapi-skill/references/blockscout-v2.openapi.json`
- A target Blockscout instance. Examples in this skill use `https://eth.blockscout.com/api/v2`.
## Scope
This skill covers a read-first explorer surface:
- address summary lookup
- address token balances
- address transaction history
- token metadata
- token holder reads
- transaction detail lookup
- block detail lookup
This skill does **not** cover:
- Blockscout GraphQL
- raw JSON-RPC proxying
- write operations or admin/configuration flows
- custom authenticated gateways beyond what the caller explicitly binds
## Authentication
Public Blockscout instances usually allow explorer reads without auth.
If you are targeting a self-hosted or gateway-protected instance, configure auth separately with standard `uxc auth` bindings for that host. This skill does not assume any default credential.
## Core Workflow
1. Use the fixed link command by default:
- `command -v blockscout-openapi-cli`
- If missing, create it:
`uxc link blockscout-openapi-cli https://eth.blockscout.com/api/v2 --schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/blockscout-openapi-skill/references/blockscout-v2.openapi.json`
- `blockscout-openapi-cli -h`
2. Inspect operation schema first:
- `blockscout-openapi-cli get:/addresses/{address_hash} -h`
- `blockscout-openapi-cli get:/tokens/{address_hash} -h`
- `blockscout-openapi-cli get:/transactions/{hash} -h`
3. Prefer narrow lookup validation before larger history reads:
- `blockscout-openapi-cli get:/blocks/{block_number_or_hash} block_number_or_hash=latest`
- `blockscout-openapi-cli get:/addresses/{address_hash} address_hash=0xd8da6bf26964af9d7eed9e03e53415d37aa96045`
- `blockscout-openapi-cli get:/tokens/{address_hash} address_hash=0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48`
4. Execute with key/value parameters:
- `blockscout-openapi-cli get:/addresses/{address_hash}/transactions address_hash=0xd8da6bf26964af9d7eed9e03e53415d37aa96045`
- `blockscout-openapi-cli get:/tokens/{address_hash}/holders address_hash=0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48`
## Operation Groups
### Address Reads
- `get:/addresses/{address_hash}`
- `get:/addresses/{address_hash}/token-balances`
- `get:/addresses/{address_hash}/transactions`
### Token, Transaction, And Block Reads
- `get:/tokens/{address_hash}`
- `get:/tokens/{address_hash}/holders`
- `get:/transactions/{hash}`
- `get:/blocks/{block_number_or_hash}`
## Multi-Instance Use
To target a different Blockscout deployment, keep the same schema and relink the command to another host that serves `/api/v2`:
```bash
uxc link blockscout-openapi-cli https://optimism.blockscout.com/api/v2 \
--schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/blockscout-openapi-skill/references/blockscout-v2.openapi.json
```
## Guardrails
- Keep automation on the JSON output envelope; do not use `--text`.
- Parse stable fields first: `ok`, `kind`, `protocol`, `data`, `error`.
- Treat this v1 skill as read-only. Do not imply transaction broadcast or contract write support.
- This schema is designed for Blockscout deployments that expose the explorer REST surface at `/api/v2`. If host help fails, check the deployment path before assuming a protocol mismatch.
- Pagination and filter options vary across deployments. Start with host help and operation help on the target instance before building large crawls.
- `blockscout-openapi-cli <operation> ...` is equivalent to `uxc <blockscout_api_v2_host> --schema-url <blockscout_openapi_schema> <operation> ...`.
## References
- Usage patterns: `references/usage-patterns.md`
- Curated OpenAPI schema: `references/blockscout-v2.openapi.json`
- Blockscout API docs: https://docs.blockscout.com/devs/apis-redirect
FILE:agents/openai.yaml
interface:
display_name: "Blockscout Explorer API"
short_description: "Operate Blockscout explorer reads via UXC + curated OpenAPI schema"
default_prompt: "Use $blockscout-openapi-skill to discover and execute Blockscout explorer read operations through UXC with instance-specific host selection and read-first guardrails."
FILE:references/blockscout-v2.openapi.json
{
"openapi": "3.0.3",
"info": {
"title": "Blockscout V2 Curated API",
"version": "1.0.0",
"description": "Curated read-only Blockscout explorer surface for UXC."
},
"servers": [
{
"url": "https://eth.blockscout.com/api/v2"
}
],
"paths": {
"/addresses/{address_hash}": {
"get": {
"operationId": "getAddress",
"summary": "Get an address summary",
"parameters": [
{
"name": "address_hash",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Address response",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
},
"/addresses/{address_hash}/token-balances": {
"get": {
"operationId": "getAddressTokenBalances",
"summary": "Get token balances for an address",
"parameters": [
{
"name": "address_hash",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Token balances response",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
},
"/addresses/{address_hash}/transactions": {
"get": {
"operationId": "getAddressTransactions",
"summary": "Get transactions for an address",
"parameters": [
{
"name": "address_hash",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Address transactions response",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
},
"/tokens/{address_hash}": {
"get": {
"operationId": "getToken",
"summary": "Get token metadata",
"parameters": [
{
"name": "address_hash",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Token response",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
},
"/tokens/{address_hash}/holders": {
"get": {
"operationId": "getTokenHolders",
"summary": "Get token holders",
"parameters": [
{
"name": "address_hash",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Token holders response",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
},
"/transactions/{hash}": {
"get": {
"operationId": "getTransaction",
"summary": "Get a transaction by hash",
"parameters": [
{
"name": "hash",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Transaction response",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
},
"/blocks/{block_number_or_hash}": {
"get": {
"operationId": "getBlock",
"summary": "Get a block by number or hash",
"parameters": [
{
"name": "block_number_or_hash",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Block response",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
}
}
}
FILE:references/usage-patterns.md
# Blockscout Explorer API Skill - Usage Patterns
## Link Setup
```bash
command -v blockscout-openapi-cli
uxc link blockscout-openapi-cli https://eth.blockscout.com/api/v2 \
--schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/blockscout-openapi-skill/references/blockscout-v2.openapi.json
blockscout-openapi-cli -h
```
## Read Examples
```bash
# Read one block
blockscout-openapi-cli get:/blocks/{block_number_or_hash} block_number_or_hash=latest
# Read one address summary
blockscout-openapi-cli get:/addresses/{address_hash} address_hash=0xd8da6bf26964af9d7eed9e03e53415d37aa96045
# Read one address token balances
blockscout-openapi-cli get:/addresses/{address_hash}/token-balances \
address_hash=0xd8da6bf26964af9d7eed9e03e53415d37aa96045
# Read one address transaction history
blockscout-openapi-cli get:/addresses/{address_hash}/transactions \
address_hash=0xd8da6bf26964af9d7eed9e03e53415d37aa96045
# Read token metadata
blockscout-openapi-cli get:/tokens/{address_hash} \
address_hash=0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
# Read token holders
blockscout-openapi-cli get:/tokens/{address_hash}/holders \
address_hash=0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
# Read transaction detail
blockscout-openapi-cli get:/transactions/{hash} \
hash=0x4e3f3bc239f496f59c3e4d4a4d5f10f7f0d6d9f4cd790beeb520d05f6f7d98ae
```
## Relink For Another Deployment
```bash
uxc link blockscout-openapi-cli https://optimism.blockscout.com/api/v2 \
--schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/blockscout-openapi-skill/references/blockscout-v2.openapi.json
```
## Fallback Equivalence
- `blockscout-openapi-cli <operation> ...` is equivalent to
`uxc <blockscout_api_v2_host> --schema-url <blockscout_openapi_schema> <operation> ...`.
FILE:scripts/validate.sh
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "BASH_SOURCE[0]")/../../.." && pwd)"
SKILL_DIR="ROOT_DIR/skills/blockscout-openapi-skill"
SKILL_FILE="SKILL_DIR/SKILL.md"
OPENAI_FILE="SKILL_DIR/agents/openai.yaml"
USAGE_FILE="SKILL_DIR/references/usage-patterns.md"
SCHEMA_FILE="SKILL_DIR/references/blockscout-v2.openapi.json"
fail() {
printf '[validate] error: %s\n' "$*" >&2
exit 1
}
need_cmd() {
command -v "$1" >/dev/null 2>&1 || fail "required command not found: $1"
}
need_cmd jq
need_cmd rg
for file in "SKILL_FILE" "OPENAI_FILE" "USAGE_FILE" "SCHEMA_FILE"; do
[[ -f "file" ]] || fail "missing required file: file"
done
jq -e '.openapi and .paths' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'invalid OpenAPI schema JSON or missing .openapi/.paths'
jq -e '.paths["/addresses/{address_hash}"] and .paths["/transactions/{hash}"]' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'OpenAPI schema missing expected Blockscout paths'
rg -q '^name:\s*blockscout-openapi-skill\s*$' "SKILL_FILE" || fail 'invalid skill name'
rg -q '^description:\s*.+' "SKILL_FILE" || fail 'missing description'
rg -q 'command -v blockscout-openapi-cli' "SKILL_FILE" || fail 'missing link-first command check'
rg -q 'uxc link blockscout-openapi-cli https://eth.blockscout.com/api/v2 --schema-url ' "SKILL_FILE" || fail 'missing fixed link create command with schema-url'
rg -q 'blockscout-openapi-cli -h' "SKILL_FILE" || fail 'missing help-first host discovery example'
rg -F -q 'blockscout-openapi-cli get:/addresses/{address_hash} -h' "SKILL_FILE" || fail 'missing operation-level help example'
rg -q 'read-only' "SKILL_FILE" || fail 'missing read-only guardrail'
rg -q 'optimism.blockscout.com/api/v2' "SKILL_FILE" "USAGE_FILE" || fail 'missing multi-instance relink example'
if rg -q -- "--args\\s+'\\{" "SKILL_FILE" "USAGE_FILE"; then
fail 'found banned legacy JSON argument pattern'
fi
rg -q '^\s*display_name:\s*"Blockscout Explorer API"\s*$' "OPENAI_FILE" || fail 'missing display_name'
rg -q '^\s*short_description:\s*".+"\s*$' "OPENAI_FILE" || fail 'missing short_description'
rg -q '^\s*default_prompt:\s*".*\$blockscout-openapi-skill.*"\s*$' "OPENAI_FILE" || fail 'default_prompt must mention $blockscout-openapi-skill'
echo "skills/blockscout-openapi-skill validation passed"
Operate CoinAPI market data reads through UXC with a curated OpenAPI schema, API-key auth, and read-first guardrails.
---
name: coinapi-openapi-skill
description: Operate CoinAPI market data reads through UXC with a curated OpenAPI schema, API-key auth, and read-first guardrails.
---
# CoinAPI REST Skill
Use this skill to run CoinAPI REST market data operations through `uxc` + OpenAPI.
Reuse the `uxc` skill for shared execution, auth, and error-handling guidance.
## Prerequisites
- `uxc` is installed and available in `PATH`.
- Network access to `https://rest.coinapi.io`.
- Access to the curated OpenAPI schema URL:
- `https://raw.githubusercontent.com/holon-run/uxc/main/skills/coinapi-openapi-skill/references/coinapi-market.openapi.json`
- A CoinAPI key.
## Scope
This skill covers a read-first market data surface:
- current exchange rates
- current quote snapshots
- latest OHLCV candles
- latest trades
- latest order books
This skill does **not** cover:
- FIX, WebSocket, or MCP transport surfaces
- write operations
- the broader CoinAPI catalog
## Authentication
CoinAPI uses `X-CoinAPI-Key` header auth.
Configure one API-key credential and bind it to `rest.coinapi.io`:
```bash
uxc auth credential set coinapi \
--auth-type api_key \
--api-key-header X-CoinAPI-Key \
--secret-env COINAPI_KEY
uxc auth binding add \
--id coinapi \
--host rest.coinapi.io \
--scheme https \
--credential coinapi \
--priority 100
```
Validate the active mapping when auth looks wrong:
```bash
uxc auth binding match https://rest.coinapi.io
```
## Core Workflow
1. Use the fixed link command by default:
- `command -v coinapi-openapi-cli`
- If missing, create it:
`uxc link coinapi-openapi-cli https://rest.coinapi.io --schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/coinapi-openapi-skill/references/coinapi-market.openapi.json`
- `coinapi-openapi-cli -h`
2. Inspect operation schema first:
- `coinapi-openapi-cli get:/v1/exchangerate/{asset_id_base}/{asset_id_quote} -h`
- `coinapi-openapi-cli get:/v1/ohlcv/{symbol_id}/latest -h`
- `coinapi-openapi-cli get:/v1/trades/{symbol_id}/latest -h`
3. Prefer narrow spot and latest reads before broader crawls:
- `coinapi-openapi-cli get:/v1/exchangerate/{asset_id_base}/{asset_id_quote} asset_id_base=BTC asset_id_quote=USD`
- `coinapi-openapi-cli get:/v1/quotes/current filter_symbol_id=BINANCE_SPOT_BTC_USDT`
4. Execute with key/value parameters:
- `coinapi-openapi-cli get:/v1/ohlcv/{symbol_id}/latest symbol_id=BINANCE_SPOT_BTC_USDT period_id=1DAY limit=10`
- `coinapi-openapi-cli get:/v1/orderbooks/{symbol_id}/latest symbol_id=BINANCE_SPOT_BTC_USDT limit_levels=20`
## Operations
- `get:/v1/exchangerate/{asset_id_base}/{asset_id_quote}`
- `get:/v1/quotes/current`
- `get:/v1/ohlcv/{symbol_id}/latest`
- `get:/v1/trades/{symbol_id}/latest`
- `get:/v1/orderbooks/{symbol_id}/latest`
## Guardrails
- Keep automation on the JSON output envelope; do not use `--text`.
- Parse stable fields first: `ok`, `kind`, `protocol`, `data`, `error`.
- Treat this v1 skill as read-only. Do not imply order entry or market connectivity support.
- Keep `filter_symbol_id`, `period_id`, `limit`, and `limit_levels` narrow unless the user explicitly wants larger pulls.
- `coinapi-openapi-cli <operation> ...` is equivalent to `uxc https://rest.coinapi.io --schema-url <coinapi_openapi_schema> <operation> ...`.
## References
- Usage patterns: `references/usage-patterns.md`
- Curated OpenAPI schema: `references/coinapi-market.openapi.json`
- CoinAPI REST docs: https://docs.coinapi.io/market-data/rest-api
FILE:agents/openai.yaml
interface:
display_name: "CoinAPI REST"
short_description: "Operate CoinAPI market data reads via UXC + curated OpenAPI schema"
default_prompt: "Use $coinapi-openapi-skill to discover and execute CoinAPI REST market data reads through UXC with X-CoinAPI-Key auth and read-first guardrails."
FILE:references/coinapi-market.openapi.json
{
"openapi": "3.0.3",
"info": {
"title": "CoinAPI Market Curated API",
"version": "1.0.0",
"description": "Curated read-only CoinAPI market data surface for UXC."
},
"servers": [
{
"url": "https://rest.coinapi.io"
}
],
"security": [
{
"coinApiKey": []
}
],
"paths": {
"/v1/exchangerate/{asset_id_base}/{asset_id_quote}": {
"get": {
"operationId": "getExchangeRate",
"summary": "Get current exchange rate",
"parameters": [
{
"name": "asset_id_base",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "asset_id_quote",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Exchange rate response",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
},
"/v1/quotes/current": {
"get": {
"operationId": "getCurrentQuotes",
"summary": "Get current quote snapshots",
"parameters": [
{
"name": "filter_symbol_id",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "limit",
"in": "query",
"schema": {
"type": "integer",
"minimum": 1
}
}
],
"responses": {
"200": {
"description": "Current quotes response",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
}
},
"/v1/ohlcv/{symbol_id}/latest": {
"get": {
"operationId": "getLatestOhlcv",
"summary": "Get latest OHLCV candles",
"parameters": [
{
"name": "symbol_id",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "period_id",
"in": "query",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "limit",
"in": "query",
"schema": {
"type": "integer",
"minimum": 1
}
}
],
"responses": {
"200": {
"description": "Latest OHLCV response",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
}
},
"/v1/trades/{symbol_id}/latest": {
"get": {
"operationId": "getLatestTrades",
"summary": "Get latest trades",
"parameters": [
{
"name": "symbol_id",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "limit",
"in": "query",
"schema": {
"type": "integer",
"minimum": 1
}
}
],
"responses": {
"200": {
"description": "Latest trades response",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
}
},
"/v1/orderbooks/{symbol_id}/latest": {
"get": {
"operationId": "getLatestOrderbook",
"summary": "Get latest order book snapshot",
"parameters": [
{
"name": "symbol_id",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "limit_levels",
"in": "query",
"schema": {
"type": "integer",
"minimum": 1
}
}
],
"responses": {
"200": {
"description": "Latest orderbook response",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
}
},
"components": {
"securitySchemes": {
"coinApiKey": {
"type": "apiKey",
"in": "header",
"name": "X-CoinAPI-Key"
}
}
}
}
FILE:references/usage-patterns.md
# CoinAPI REST Skill - Usage Patterns
## Link Setup
```bash
command -v coinapi-openapi-cli
uxc link coinapi-openapi-cli https://rest.coinapi.io \
--schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/coinapi-openapi-skill/references/coinapi-market.openapi.json
coinapi-openapi-cli -h
```
## Auth Setup
```bash
uxc auth credential set coinapi \
--auth-type api_key \
--api-key-header X-CoinAPI-Key \
--secret-env COINAPI_KEY
uxc auth binding add \
--id coinapi \
--host rest.coinapi.io \
--scheme https \
--credential coinapi \
--priority 100
```
Validate the binding:
```bash
uxc auth binding match https://rest.coinapi.io
```
## Read Examples
```bash
# Read current exchange rate
coinapi-openapi-cli get:/v1/exchangerate/{asset_id_base}/{asset_id_quote} \
asset_id_base=BTC \
asset_id_quote=USD
# Read current quote snapshots
coinapi-openapi-cli get:/v1/quotes/current filter_symbol_id=BINANCE_SPOT_BTC_USDT
# Read latest OHLCV candles
coinapi-openapi-cli get:/v1/ohlcv/{symbol_id}/latest \
symbol_id=BINANCE_SPOT_BTC_USDT \
period_id=1DAY \
limit=10
# Read latest trades
coinapi-openapi-cli get:/v1/trades/{symbol_id}/latest \
symbol_id=BINANCE_SPOT_BTC_USDT \
limit=20
# Read latest order book snapshot
coinapi-openapi-cli get:/v1/orderbooks/{symbol_id}/latest \
symbol_id=BINANCE_SPOT_BTC_USDT \
limit_levels=20
```
## Fallback Equivalence
- `coinapi-openapi-cli <operation> ...` is equivalent to
`uxc https://rest.coinapi.io --schema-url <coinapi_openapi_schema> <operation> ...`.
FILE:scripts/validate.sh
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "BASH_SOURCE[0]")/../../.." && pwd)"
SKILL_DIR="ROOT_DIR/skills/coinapi-openapi-skill"
SKILL_FILE="SKILL_DIR/SKILL.md"
OPENAI_FILE="SKILL_DIR/agents/openai.yaml"
USAGE_FILE="SKILL_DIR/references/usage-patterns.md"
SCHEMA_FILE="SKILL_DIR/references/coinapi-market.openapi.json"
fail() {
printf '[validate] error: %s\n' "$*" >&2
exit 1
}
need_cmd() {
command -v "$1" >/dev/null 2>&1 || fail "required command not found: $1"
}
need_cmd jq
need_cmd rg
for file in "SKILL_FILE" "OPENAI_FILE" "USAGE_FILE" "SCHEMA_FILE"; do
[[ -f "file" ]] || fail "missing required file: file"
done
jq -e '.openapi and .paths and .components' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'invalid OpenAPI schema JSON or missing .openapi/.paths/.components'
jq -e '.paths["/v1/exchangerate/{asset_id_base}/{asset_id_quote}"] and .paths["/v1/trades/{symbol_id}/latest"]' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'OpenAPI schema missing expected CoinAPI paths'
rg -q '^name:\s*coinapi-openapi-skill\s*$' "SKILL_FILE" || fail 'invalid skill name'
rg -q '^description:\s*.+' "SKILL_FILE" || fail 'missing description'
rg -q 'command -v coinapi-openapi-cli' "SKILL_FILE" || fail 'missing link-first command check'
rg -q 'uxc link coinapi-openapi-cli https://rest.coinapi.io --schema-url ' "SKILL_FILE" || fail 'missing fixed link create command with schema-url'
rg -F -q 'coinapi-openapi-cli get:/v1/exchangerate/{asset_id_base}/{asset_id_quote} -h' "SKILL_FILE" || fail 'missing operation-level help example'
rg -q -- '--api-key-header X-CoinAPI-Key' "SKILL_FILE" || fail 'missing X-CoinAPI-Key auth setup'
rg -q 'uxc auth binding match https://rest.coinapi.io' "SKILL_FILE" || fail 'missing binding match check'
rg -q 'read-only' "SKILL_FILE" || fail 'missing read-only guardrail'
if rg -q -- "--args\\s+'\\{" "SKILL_FILE" "USAGE_FILE"; then
fail 'found banned legacy JSON argument pattern'
fi
rg -q '^\s*display_name:\s*"CoinAPI REST"\s*$' "OPENAI_FILE" || fail 'missing display_name'
rg -q '^\s*short_description:\s*".+"\s*$' "OPENAI_FILE" || fail 'missing short_description'
rg -q '^\s*default_prompt:\s*".*\$coinapi-openapi-skill.*"\s*$' "OPENAI_FILE" || fail 'default_prompt must mention $coinapi-openapi-skill'
echo "skills/coinapi-openapi-skill validation passed"
Operate CoinGecko and GeckoTerminal market data APIs through UXC with a curated OpenAPI schema, API-key auth, and read-first guardrails.
---
name: coingecko-openapi-skill
description: Operate CoinGecko and GeckoTerminal market data APIs through UXC with a curated OpenAPI schema, API-key auth, and read-first guardrails.
---
# CoinGecko And GeckoTerminal Skill
Use this skill to run CoinGecko market data and GeckoTerminal onchain DEX operations through `uxc` + OpenAPI.
Reuse the `uxc` skill for shared execution, auth, and error-handling guidance.
## Prerequisites
- `uxc` is installed and available in `PATH`.
- Network access to `https://api.coingecko.com/api/v3`.
- Access to the curated OpenAPI schema URL:
- `https://raw.githubusercontent.com/holon-run/uxc/main/skills/coingecko-openapi-skill/references/coingecko-market.openapi.json`
- A CoinGecko Demo API key.
## Scope
This skill covers a read-first market data surface:
- API liveness checks
- spot price lookup
- asset ID discovery
- market screener reads
- trending reads
- GeckoTerminal network discovery
- onchain token price lookup
- trending pool reads
This skill does **not** cover:
- paid or enterprise-only method families beyond the selected v1 scope
- historical chart or OHLC families
- portfolio, NFT, or onchain trade execution
- the full CoinGecko or GeckoTerminal API
## Authentication
The default host uses CoinGecko Demo auth with `x-cg-demo-api-key`.
Configure one API-key credential and bind it to `api.coingecko.com/api/v3`:
```bash
uxc auth credential set coingecko-demo \
--auth-type api_key \
--api-key-header x-cg-demo-api-key \
--secret-env COINGECKO_DEMO_API_KEY
uxc auth binding add \
--id coingecko-demo \
--host api.coingecko.com \
--path-prefix /api/v3 \
--scheme https \
--credential coingecko-demo \
--priority 100
```
Validate the active mapping when auth looks wrong:
```bash
uxc auth binding match https://api.coingecko.com/api/v3
```
### Pro Host Override
If you have a Pro plan, keep the same curated schema and create a separate credential, binding, and link:
```bash
uxc auth credential set coingecko-pro \
--auth-type api_key \
--api-key-header x-cg-pro-api-key \
--secret-env COINGECKO_PRO_API_KEY
uxc auth binding add \
--id coingecko-pro \
--host pro-api.coingecko.com \
--path-prefix /api/v3 \
--scheme https \
--credential coingecko-pro \
--priority 100
uxc link coingecko-pro-openapi-cli https://pro-api.coingecko.com/api/v3 \
--schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/coingecko-openapi-skill/references/coingecko-market.openapi.json
```
## Core Workflow
1. Use the fixed link command by default:
- `command -v coingecko-openapi-cli`
- If missing, create it:
`uxc link coingecko-openapi-cli https://api.coingecko.com/api/v3 --schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/coingecko-openapi-skill/references/coingecko-market.openapi.json`
- `coingecko-openapi-cli -h`
2. Inspect operation schema first:
- `coingecko-openapi-cli get:/simple/price -h`
- `coingecko-openapi-cli get:/coins/markets -h`
- `coingecko-openapi-cli get:/onchain/simple/networks/{network}/token_price/{addresses} -h`
3. Prefer narrow read validation before broader reads:
- `coingecko-openapi-cli get:/ping`
- `coingecko-openapi-cli get:/coins/list include_platform=false`
- `coingecko-openapi-cli get:/onchain/networks`
4. Execute with key/value parameters:
- `coingecko-openapi-cli get:/simple/price ids=bitcoin,ethereum vs_currencies=usd`
- `coingecko-openapi-cli get:/coins/markets vs_currency=usd ids=bitcoin,ethereum order=market_cap_desc per_page=10 page=1`
- `coingecko-openapi-cli get:/onchain/simple/networks/{network}/token_price/{addresses} network=eth addresses=0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48`
## Operation Groups
### Market Data
- `get:/ping`
- `get:/simple/price`
- `get:/coins/list`
- `get:/coins/markets`
- `get:/search/trending`
### GeckoTerminal Onchain Data
- `get:/onchain/networks`
- `get:/onchain/simple/networks/{network}/token_price/{addresses}`
- `get:/onchain/networks/trending_pools`
## Guardrails
- Keep automation on the JSON output envelope; do not use `--text`.
- Parse stable fields first: `ok`, `kind`, `protocol`, `data`, `error`.
- Treat this v1 skill as read-only. Do not imply wallet, trading, or portfolio mutation support.
- Demo and Pro hosts use different API-key headers. If the default Demo credential fails against the Pro host, create a separate Pro credential rather than reusing the Demo header name.
- The Pro host needs its own auth binding on `pro-api.coingecko.com/api/v3`; creating only a credential is not enough for linked calls to send `x-cg-pro-api-key`.
- CoinGecko public and Demo limits are tighter than Pro. Keep default examples narrow and avoid large paginated loops without explicit user intent.
- The GeckoTerminal endpoints in this schema share the same API root and auth flow as the rest of the curated CoinGecko host contract.
- `coingecko-openapi-cli <operation> ...` is equivalent to `uxc https://api.coingecko.com/api/v3 --schema-url <coingecko_openapi_schema> <operation> ...`.
## References
- Usage patterns: `references/usage-patterns.md`
- Curated OpenAPI schema: `references/coingecko-market.openapi.json`
- CoinGecko API docs: https://docs.coingecko.com/reference/endpoint-overview
- Authentication docs: https://docs.coingecko.com/reference/authentication
FILE:agents/openai.yaml
interface:
display_name: "CoinGecko And GeckoTerminal"
short_description: "Operate CoinGecko market data and GeckoTerminal onchain reads via UXC + curated OpenAPI schema"
default_prompt: "Use $coingecko-openapi-skill to discover and execute CoinGecko and GeckoTerminal read-only market data operations through UXC with Demo API-key auth, optional Pro override, and read-first guardrails."
FILE:references/coingecko-market.openapi.json
{
"openapi": "3.0.3",
"info": {
"title": "CoinGecko And GeckoTerminal Curated API",
"version": "1.0.0",
"description": "Curated read-only CoinGecko and GeckoTerminal market data surface for UXC."
},
"servers": [
{
"url": "https://api.coingecko.com/api/v3"
}
],
"security": [
{
"coinGeckoDemoApiKey": []
},
{
"coinGeckoProApiKey": []
}
],
"paths": {
"/ping": {
"get": {
"operationId": "ping",
"summary": "Ping the CoinGecko API",
"responses": {
"200": {
"description": "Ping response",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
},
"/simple/price": {
"get": {
"operationId": "getSimplePrice",
"summary": "Get current prices for one or more assets",
"parameters": [
{
"name": "ids",
"in": "query",
"required": true,
"schema": {
"type": "string"
},
"description": "Comma-separated CoinGecko asset IDs."
},
{
"name": "vs_currencies",
"in": "query",
"required": true,
"schema": {
"type": "string"
},
"description": "Comma-separated quote currencies."
},
{
"name": "include_market_cap",
"in": "query",
"schema": {
"type": "boolean"
}
},
{
"name": "include_24hr_vol",
"in": "query",
"schema": {
"type": "boolean"
}
},
{
"name": "include_24hr_change",
"in": "query",
"schema": {
"type": "boolean"
}
},
{
"name": "include_last_updated_at",
"in": "query",
"schema": {
"type": "boolean"
}
},
{
"name": "precision",
"in": "query",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Simple price response",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
},
"/coins/list": {
"get": {
"operationId": "listCoins",
"summary": "List supported asset IDs",
"parameters": [
{
"name": "include_platform",
"in": "query",
"schema": {
"type": "boolean"
}
}
],
"responses": {
"200": {
"description": "Asset list response",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
}
},
"/coins/markets": {
"get": {
"operationId": "getCoinMarkets",
"summary": "Get market rows for one or more assets",
"parameters": [
{
"name": "vs_currency",
"in": "query",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "ids",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "names",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "symbols",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "category",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "order",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "per_page",
"in": "query",
"schema": {
"type": "integer",
"minimum": 1,
"maximum": 250
}
},
{
"name": "page",
"in": "query",
"schema": {
"type": "integer",
"minimum": 1
}
},
{
"name": "sparkline",
"in": "query",
"schema": {
"type": "boolean"
}
},
{
"name": "price_change_percentage",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "locale",
"in": "query",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Coin markets response",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
}
},
"/search/trending": {
"get": {
"operationId": "getTrendingSearch",
"summary": "Get trending search data",
"responses": {
"200": {
"description": "Trending response",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
},
"/onchain/networks": {
"get": {
"operationId": "listOnchainNetworks",
"summary": "List GeckoTerminal networks",
"responses": {
"200": {
"description": "Onchain networks response",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
},
"/onchain/simple/networks/{network}/token_price/{addresses}": {
"get": {
"operationId": "getOnchainSimpleTokenPrice",
"summary": "Get onchain token prices by network and address list",
"parameters": [
{
"name": "network",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "addresses",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Comma-separated token contract addresses."
},
{
"name": "mcap_fdv_fallback",
"in": "query",
"schema": {
"type": "boolean"
}
}
],
"responses": {
"200": {
"description": "Onchain token price response",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
},
"/onchain/networks/trending_pools": {
"get": {
"operationId": "getTrendingPools",
"summary": "Get trending GeckoTerminal pools",
"responses": {
"200": {
"description": "Trending pools response",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
}
},
"components": {
"securitySchemes": {
"coinGeckoDemoApiKey": {
"type": "apiKey",
"in": "header",
"name": "x-cg-demo-api-key"
},
"coinGeckoProApiKey": {
"type": "apiKey",
"in": "header",
"name": "x-cg-pro-api-key"
}
}
}
}
FILE:references/usage-patterns.md
# CoinGecko And GeckoTerminal Skill - Usage Patterns
## Link Setup
```bash
command -v coingecko-openapi-cli
uxc link coingecko-openapi-cli https://api.coingecko.com/api/v3 \
--schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/coingecko-openapi-skill/references/coingecko-market.openapi.json
coingecko-openapi-cli -h
```
## Demo Auth Setup
```bash
uxc auth credential set coingecko-demo \
--auth-type api_key \
--api-key-header x-cg-demo-api-key \
--secret-env COINGECKO_DEMO_API_KEY
uxc auth binding add \
--id coingecko-demo \
--host api.coingecko.com \
--path-prefix /api/v3 \
--scheme https \
--credential coingecko-demo \
--priority 100
```
Validate the binding:
```bash
uxc auth binding match https://api.coingecko.com/api/v3
```
## Pro Host Override
```bash
uxc auth credential set coingecko-pro \
--auth-type api_key \
--api-key-header x-cg-pro-api-key \
--secret-env COINGECKO_PRO_API_KEY
uxc auth binding add \
--id coingecko-pro \
--host pro-api.coingecko.com \
--path-prefix /api/v3 \
--scheme https \
--credential coingecko-pro \
--priority 100
uxc link coingecko-pro-openapi-cli https://pro-api.coingecko.com/api/v3 \
--schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/coingecko-openapi-skill/references/coingecko-market.openapi.json
```
## Read Examples
```bash
# Confirm API liveness
coingecko-openapi-cli get:/ping
# Read spot prices for two assets
coingecko-openapi-cli get:/simple/price ids=bitcoin,ethereum vs_currencies=usd include_24hr_change=true
# Discover asset IDs
coingecko-openapi-cli get:/coins/list include_platform=false
# Read market screener rows
coingecko-openapi-cli get:/coins/markets vs_currency=usd ids=bitcoin,ethereum order=market_cap_desc per_page=10 page=1
# Read trending assets
coingecko-openapi-cli get:/search/trending
# List supported GeckoTerminal networks
coingecko-openapi-cli get:/onchain/networks
# Read onchain token prices for one network and one or more addresses
coingecko-openapi-cli get:/onchain/simple/networks/{network}/token_price/{addresses} \
network=eth \
addresses=0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
# Read trending pools across supported onchain networks
coingecko-openapi-cli get:/onchain/networks/trending_pools
```
## Fallback Equivalence
- `coingecko-openapi-cli <operation> ...` is equivalent to
`uxc https://api.coingecko.com/api/v3 --schema-url <coingecko_openapi_schema> <operation> ...`.
FILE:scripts/validate.sh
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "BASH_SOURCE[0]")/../../.." && pwd)"
SKILL_DIR="ROOT_DIR/skills/coingecko-openapi-skill"
SKILL_FILE="SKILL_DIR/SKILL.md"
OPENAI_FILE="SKILL_DIR/agents/openai.yaml"
USAGE_FILE="SKILL_DIR/references/usage-patterns.md"
SCHEMA_FILE="SKILL_DIR/references/coingecko-market.openapi.json"
fail() {
printf '[validate] error: %s\n' "$*" >&2
exit 1
}
need_cmd() {
command -v "$1" >/dev/null 2>&1 || fail "required command not found: $1"
}
need_cmd jq
need_cmd rg
for file in "SKILL_FILE" "OPENAI_FILE" "USAGE_FILE" "SCHEMA_FILE"; do
[[ -f "file" ]] || fail "missing required file: file"
done
jq -e '.openapi and .paths and .components' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'invalid OpenAPI schema JSON or missing .openapi/.paths/.components'
jq -e '.paths["/simple/price"] and .paths["/onchain/networks"]' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'OpenAPI schema missing expected CoinGecko or GeckoTerminal paths'
rg -q '^name:\s*coingecko-openapi-skill\s*$' "SKILL_FILE" || fail 'invalid skill name'
rg -q '^description:\s*.+' "SKILL_FILE" || fail 'missing description'
rg -q 'command -v coingecko-openapi-cli' "SKILL_FILE" || fail 'missing link-first command check'
rg -q 'uxc link coingecko-openapi-cli https://api.coingecko.com/api/v3 --schema-url ' "SKILL_FILE" || fail 'missing fixed link create command with schema-url'
rg -q 'coingecko-openapi-cli -h' "SKILL_FILE" || fail 'missing help-first host discovery example'
rg -q 'coingecko-openapi-cli get:/simple/price -h' "SKILL_FILE" || fail 'missing operation-level help example'
rg -q -- '--api-key-header x-cg-demo-api-key' "SKILL_FILE" || fail 'missing demo api key setup'
rg -q 'uxc auth binding match https://api.coingecko.com/api/v3' "SKILL_FILE" || fail 'missing binding match check'
rg -q 'x-cg-pro-api-key' "SKILL_FILE" || fail 'missing pro override guidance'
rg -q 'pro-api.coingecko.com' "SKILL_FILE" "USAGE_FILE" || fail 'missing pro host binding guidance'
rg -q 'read-only' "SKILL_FILE" || fail 'missing read-only guardrail'
if rg -q -- "--args\\s+'\\{" "SKILL_FILE" "USAGE_FILE"; then
fail 'found banned legacy JSON argument pattern'
fi
rg -q '^\s*display_name:\s*"CoinGecko And GeckoTerminal"\s*$' "OPENAI_FILE" || fail 'missing display_name'
rg -q '^\s*short_description:\s*".+"\s*$' "OPENAI_FILE" || fail 'missing short_description'
rg -q '^\s*default_prompt:\s*".*\$coingecko-openapi-skill.*"\s*$' "OPENAI_FILE" || fail 'default_prompt must mention $coingecko-openapi-skill'
echo "skills/coingecko-openapi-skill validation passed"
Operate Alchemy Prices API reads through UXC with a curated OpenAPI schema, path-templated API-key auth, and read-first guardrails.
---
name: alchemy-openapi-skill
description: Operate Alchemy Prices API reads through UXC with a curated OpenAPI schema, path-templated API-key auth, and read-first guardrails.
---
# Alchemy Prices API Skill
Use this skill to run Alchemy Prices API operations through `uxc` + OpenAPI.
Reuse the `uxc` skill for shared execution, auth, and error-handling guidance.
## Prerequisites
- `uxc` is installed and available in `PATH`.
- Network access to `https://api.g.alchemy.com`.
- Access to the curated OpenAPI schema URL:
- `https://raw.githubusercontent.com/holon-run/uxc/main/skills/alchemy-openapi-skill/references/alchemy-prices.openapi.json`
- An Alchemy API key.
## Scope
This v1 skill intentionally covers the narrow Prices API surface:
- token price lookup by symbol
- token price lookup by contract address
- historical token prices
This skill does **not** cover:
- node JSON-RPC
- NFT or portfolio APIs
- write operations
- the broader Alchemy API surface
- multi-symbol batch lookup in one `uxc` call
## Authentication
Alchemy Prices API places the API key in the request path: `/prices/v1/{apiKey}/...`.
Configure one API-key credential with a request path prefix template:
```bash
uxc auth credential set alchemy-prices \
--auth-type api_key \
--secret-env ALCHEMY_API_KEY \
--path-prefix-template "/prices/v1/{{secret}}"
uxc auth binding add \
--id alchemy-prices \
--host api.g.alchemy.com \
--scheme https \
--credential alchemy-prices \
--priority 100
```
Validate the active mapping when auth looks wrong:
```bash
uxc auth binding match https://api.g.alchemy.com
```
## Core Workflow
1. Use the fixed link command by default:
- `command -v alchemy-openapi-cli`
- If missing, create it:
`uxc link alchemy-openapi-cli https://api.g.alchemy.com --schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/alchemy-openapi-skill/references/alchemy-prices.openapi.json`
- `alchemy-openapi-cli -h`
2. Inspect operation schema first:
- `alchemy-openapi-cli get:/tokens/by-symbol -h`
- `alchemy-openapi-cli post:/tokens/by-address -h`
- `alchemy-openapi-cli post:/tokens/historical -h`
3. Start with narrow single-asset reads before batch historical requests:
- `alchemy-openapi-cli get:/tokens/by-symbol symbols=ETH currency=USD`
- `alchemy-openapi-cli post:/tokens/by-address '{"addresses":[{"network":"eth-mainnet","address":"0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"}],"currency":"USD"}'`
4. Use positional JSON only for the POST endpoints:
- `alchemy-openapi-cli post:/tokens/historical '{"symbol":"ETH","startTime":"2025-01-01T00:00:00Z","endTime":"2025-01-07T00:00:00Z","interval":"1d","currency":"USD"}'`
## Operations
- `get:/tokens/by-symbol`
- `post:/tokens/by-address`
- `post:/tokens/historical`
## Guardrails
- Keep automation on the JSON output envelope; do not use `--text`.
- Parse stable fields first: `ok`, `kind`, `protocol`, `data`, `error`.
- Treat this v1 skill as read-only and prices-only. Do not imply RPC, trade execution, or wallet mutation support.
- API keys are sensitive because they appear in the request path. Use `--secret-env` or `--secret-op`, not shell history literals, when possible.
- `/tokens/by-symbol` is query-based in the live API.
- The live API supports repeated `symbols=` parameters, but this v1 skill intentionally narrows that endpoint to a single `symbols=<TOKEN>` query because current `uxc` query argument handling does not reliably execute array-shaped query parameters.
- Historical requests can expand quickly. Keep time windows tight unless the user explicitly wants a larger backfill.
- `alchemy-openapi-cli <operation> ...` is equivalent to `uxc https://api.g.alchemy.com --schema-url <alchemy_openapi_schema> <operation> ...`.
## References
- Usage patterns: `references/usage-patterns.md`
- Curated OpenAPI schema: `references/alchemy-prices.openapi.json`
- Alchemy Prices API docs: https://www.alchemy.com/docs/reference/prices-api
- Prices API endpoints: https://www.alchemy.com/docs/reference/prices-api-endpoints
FILE:agents/openai.yaml
interface:
display_name: "Alchemy Prices API"
short_description: "Operate Alchemy Prices API reads via UXC + curated OpenAPI schema"
default_prompt: "Use $alchemy-openapi-skill to discover and execute Alchemy Prices API reads through UXC with path-templated API-key auth and read-first guardrails."
FILE:references/alchemy-prices.openapi.json
{
"openapi": "3.0.3",
"info": {
"title": "Alchemy Prices Curated API",
"version": "1.0.0",
"description": "Curated read-only Alchemy Prices API surface for UXC."
},
"servers": [
{
"url": "https://api.g.alchemy.com"
}
],
"paths": {
"/tokens/by-symbol": {
"get": {
"operationId": "getPricesBySymbol",
"summary": "Get token prices by symbol",
"parameters": [
{
"name": "symbols",
"in": "query",
"required": true,
"description": "A single token symbol. The live API supports repeated symbols query parameters, but this curated schema keeps v1 to one symbol per call so it remains directly executable through UXC.",
"schema": {
"type": "string"
}
},
{
"name": "currency",
"in": "query",
"required": false,
"schema": {
"type": "string",
"default": "USD"
}
}
],
"responses": {
"200": {
"description": "Prices by symbol response",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
},
"/tokens/by-address": {
"post": {
"operationId": "getPricesByAddress",
"summary": "Get token prices by contract address",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"addresses"
],
"properties": {
"addresses": {
"type": "array",
"items": {
"type": "object",
"properties": {
"network": {
"type": "string"
},
"address": {
"type": "string"
}
},
"required": [
"network",
"address"
],
"additionalProperties": true
}
},
"currency": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"responses": {
"200": {
"description": "Prices by address response",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
},
"/tokens/historical": {
"post": {
"operationId": "getHistoricalPrices",
"summary": "Get historical token prices",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"symbol": {
"type": "string"
},
"address": {
"type": "string"
},
"network": {
"type": "string"
},
"startTime": {
"type": "string"
},
"endTime": {
"type": "string"
},
"interval": {
"type": "string"
},
"currency": {
"type": "string"
}
},
"additionalProperties": true
}
}
}
},
"responses": {
"200": {
"description": "Historical prices response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"symbol": {
"type": "string"
},
"currency": {
"type": "string"
},
"data": {
"type": "array",
"items": {
"type": "object",
"properties": {
"value": {
"type": "string"
},
"timestamp": {
"type": "string"
}
},
"additionalProperties": true
}
}
},
"additionalProperties": true
}
}
}
}
}
}
}
}
}
FILE:references/usage-patterns.md
# Alchemy Prices API Skill - Usage Patterns
## Link Setup
```bash
command -v alchemy-openapi-cli
uxc link alchemy-openapi-cli https://api.g.alchemy.com \
--schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/alchemy-openapi-skill/references/alchemy-prices.openapi.json
alchemy-openapi-cli -h
```
## Auth Setup
```bash
uxc auth credential set alchemy-prices \
--auth-type api_key \
--secret-env ALCHEMY_API_KEY \
--path-prefix-template "/prices/v1/{{secret}}"
uxc auth binding add \
--id alchemy-prices \
--host api.g.alchemy.com \
--scheme https \
--credential alchemy-prices \
--priority 100
```
Validate the binding:
```bash
uxc auth binding match https://api.g.alchemy.com
```
## Read Examples
```bash
# Read token prices by symbol
alchemy-openapi-cli get:/tokens/by-symbol symbols=ETH currency=USD
# Read token prices by contract address
alchemy-openapi-cli post:/tokens/by-address '{"addresses":[{"network":"eth-mainnet","address":"0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"}],"currency":"USD"}'
# Read historical token prices
alchemy-openapi-cli post:/tokens/historical '{"symbol":"ETH","startTime":"2025-01-01T00:00:00Z","endTime":"2025-01-07T00:00:00Z","interval":"1d","currency":"USD"}'
```
## Fallback Equivalence
- `alchemy-openapi-cli <operation> ...` is equivalent to
`uxc https://api.g.alchemy.com --schema-url <alchemy_openapi_schema> <operation> ...`.
## Notes
- The live API can accept repeated `symbols=` query parameters, but this curated v1 schema keeps `get:/tokens/by-symbol` to one symbol per call so it remains directly executable through `uxc`.
FILE:scripts/validate.sh
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "BASH_SOURCE[0]")/../../.." && pwd)"
SKILL_DIR="ROOT_DIR/skills/alchemy-openapi-skill"
SKILL_FILE="SKILL_DIR/SKILL.md"
OPENAI_FILE="SKILL_DIR/agents/openai.yaml"
USAGE_FILE="SKILL_DIR/references/usage-patterns.md"
SCHEMA_FILE="SKILL_DIR/references/alchemy-prices.openapi.json"
fail() {
printf '[validate] error: %s\n' "$*" >&2
exit 1
}
need_cmd() {
command -v "$1" >/dev/null 2>&1 || fail "required command not found: $1"
}
need_cmd jq
need_cmd rg
for file in "SKILL_FILE" "OPENAI_FILE" "USAGE_FILE" "SCHEMA_FILE"; do
[[ -f "file" ]] || fail "missing required file: file"
done
jq -e '.openapi and .paths' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'invalid OpenAPI schema JSON or missing .openapi/.paths'
jq -e '.paths["/tokens/by-symbol"] and .paths["/tokens/by-address"] and .paths["/tokens/historical"]' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'OpenAPI schema missing expected Alchemy paths'
jq -e '.paths["/tokens/by-symbol"].get and .paths["/tokens/by-address"].post and .paths["/tokens/historical"].post' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'OpenAPI schema must expose GET /tokens/by-symbol and POST /tokens/by-address,/tokens/historical'
rg -q '^name:\s*alchemy-openapi-skill\s*$' "SKILL_FILE" || fail 'invalid skill name'
rg -q '^description:\s*.+' "SKILL_FILE" || fail 'missing description'
rg -q 'command -v alchemy-openapi-cli' "SKILL_FILE" || fail 'missing link-first command check'
rg -q 'uxc link alchemy-openapi-cli https://api.g.alchemy.com --schema-url ' "SKILL_FILE" || fail 'missing fixed link create command with schema-url'
rg -F -q 'alchemy-openapi-cli get:/tokens/by-symbol -h' "SKILL_FILE" || fail 'missing operation-level help example'
rg -q -- '--path-prefix-template "/prices/v1/\{\{secret\}\}"' "SKILL_FILE" || fail 'missing path-prefix auth setup'
rg -q 'uxc auth binding match https://api.g.alchemy.com' "SKILL_FILE" || fail 'missing binding match check'
rg -q 'prices-only' "SKILL_FILE" || fail 'missing prices-only guardrail'
rg -q 'single `symbols=<TOKEN>` query' "SKILL_FILE" || fail 'missing by-symbol single-symbol guidance'
if rg -q -- "--args\\s+'\\{" "SKILL_FILE" "USAGE_FILE"; then
fail 'found banned legacy JSON argument pattern'
fi
rg -q '^\s*display_name:\s*"Alchemy Prices API"\s*$' "OPENAI_FILE" || fail 'missing display_name'
rg -q '^\s*short_description:\s*".+"\s*$' "OPENAI_FILE" || fail 'missing short_description'
rg -q '^\s*default_prompt:\s*".*\$alchemy-openapi-skill.*"\s*$' "OPENAI_FILE" || fail 'default_prompt must mention $alchemy-openapi-skill'
echo "skills/alchemy-openapi-skill validation passed"
Operate Chainbase indexed wallet and token reads through UXC with a curated OpenAPI schema, API-key auth, and read-first guardrails.
---
name: chainbase-openapi-skill
description: Operate Chainbase indexed wallet and token reads through UXC with a curated OpenAPI schema, API-key auth, and read-first guardrails.
---
# Chainbase Web3 API Skill
Use this skill to run Chainbase indexed data operations through `uxc` + OpenAPI.
Reuse the `uxc` skill for shared execution, auth, and error-handling guidance.
## Prerequisites
- `uxc` is installed and available in `PATH`.
- Network access to `https://api.chainbase.online`.
- Access to the curated OpenAPI schema URL:
- `https://raw.githubusercontent.com/holon-run/uxc/main/skills/chainbase-openapi-skill/references/chainbase-web3.openapi.json`
- A Chainbase API key.
## Scope
This skill covers a read-first indexed data surface:
- account native balance lookup
- account token balances
- account transaction history
- token metadata
- token holder reads
- token price lookup
- transaction detail lookup
This skill does **not** cover:
- raw chain RPC methods
- write or transaction submission flows
- the broader Chainbase data product surface beyond the selected Web3 API reads
## Authentication
Chainbase uses `X-API-KEY` header auth.
Configure one API-key credential and bind it to `api.chainbase.online`:
```bash
uxc auth credential set chainbase \
--auth-type api_key \
--api-key-header X-API-KEY \
--secret-env CHAINBASE_API_KEY
uxc auth binding add \
--id chainbase \
--host api.chainbase.online \
--scheme https \
--credential chainbase \
--priority 100
```
Validate the active mapping when auth looks wrong:
```bash
uxc auth binding match https://api.chainbase.online
```
## Core Workflow
1. Use the fixed link command by default:
- `command -v chainbase-openapi-cli`
- If missing, create it:
`uxc link chainbase-openapi-cli https://api.chainbase.online --schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/chainbase-openapi-skill/references/chainbase-web3.openapi.json`
- `chainbase-openapi-cli -h`
2. Inspect operation schema first:
- `chainbase-openapi-cli get:/v1/account/balance -h`
- `chainbase-openapi-cli get:/v1/account/tokens -h`
- `chainbase-openapi-cli get:/v1/token/metadata -h`
3. Prefer narrow account validation before broader reads:
- `chainbase-openapi-cli get:/v1/account/balance chain_id=1 address=0xd8da6bf26964af9d7eed9e03e53415d37aa96045`
- `chainbase-openapi-cli get:/v1/token/price chain_id=1 contract_address=0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48`
- `chainbase-openapi-cli get:/v1/tx/detail chain_id=1 tx_hash=0x4e3f3bc239f496f59c3e4d4a4d5f10f7f0d6d9f4cd790beeb520d05f6f7d98ae`
4. Execute with key/value parameters:
- `chainbase-openapi-cli get:/v1/account/tokens chain_id=1 address=0xd8da6bf26964af9d7eed9e03e53415d37aa96045 page=1 limit=20`
- `chainbase-openapi-cli get:/v1/token/holders chain_id=1 contract_address=0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48 page=1 limit=20`
## Operation Groups
### Account Reads
- `get:/v1/account/balance`
- `get:/v1/account/tokens`
- `get:/v1/account/txs`
### Token And Transaction Reads
- `get:/v1/token/metadata`
- `get:/v1/token/holders`
- `get:/v1/token/price`
- `get:/v1/tx/detail`
## Guardrails
- Keep automation on the JSON output envelope; do not use `--text`.
- Parse stable fields first: `ok`, `kind`, `protocol`, `data`, `error`.
- Treat this v1 skill as read-only. Do not imply RPC write methods, mempool send, or signing support.
- Chainbase has multiple product surfaces. This skill is intentionally limited to indexed HTTP reads on `https://api.chainbase.online`.
- Start with small `page` and `limit` values before building large crawls.
- `chainbase-openapi-cli <operation> ...` is equivalent to `uxc https://api.chainbase.online --schema-url <chainbase_openapi_schema> <operation> ...`.
## References
- Usage patterns: `references/usage-patterns.md`
- Curated OpenAPI schema: `references/chainbase-web3.openapi.json`
- Chainbase auth docs: https://docs.chainbase.com/quickstart/authenticate-your-api-key
- Chainbase Web3 API docs: https://docs.chainbase.com/api-reference/web3-api/balance
FILE:agents/openai.yaml
interface:
display_name: "Chainbase Web3 API"
short_description: "Operate Chainbase indexed wallet and token reads via UXC + curated OpenAPI schema"
default_prompt: "Use $chainbase-openapi-skill to discover and execute Chainbase indexed Web3 API reads through UXC with X-API-KEY auth and read-first guardrails."
FILE:references/chainbase-web3.openapi.json
{
"openapi": "3.0.3",
"info": {
"title": "Chainbase Web3 Curated API",
"version": "1.0.0",
"description": "Curated read-only Chainbase Web3 API surface for UXC."
},
"servers": [
{
"url": "https://api.chainbase.online"
}
],
"security": [
{
"chainbaseApiKey": []
}
],
"paths": {
"/v1/account/balance": {
"get": {
"operationId": "getAccountBalance",
"summary": "Get native balance for an account",
"parameters": [
{
"name": "chain_id",
"in": "query",
"required": true,
"schema": {
"type": "integer"
}
},
{
"name": "address",
"in": "query",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Account balance response",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
},
"/v1/account/tokens": {
"get": {
"operationId": "getAccountTokens",
"summary": "Get token balances for an account",
"parameters": [
{
"name": "chain_id",
"in": "query",
"required": true,
"schema": {
"type": "integer"
}
},
{
"name": "address",
"in": "query",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "page",
"in": "query",
"schema": {
"type": "integer",
"minimum": 1
}
},
{
"name": "limit",
"in": "query",
"schema": {
"type": "integer",
"minimum": 1
}
}
],
"responses": {
"200": {
"description": "Account tokens response",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
},
"/v1/account/txs": {
"get": {
"operationId": "getAccountTransactions",
"summary": "Get transactions for an account",
"parameters": [
{
"name": "chain_id",
"in": "query",
"required": true,
"schema": {
"type": "integer"
}
},
{
"name": "address",
"in": "query",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "page",
"in": "query",
"schema": {
"type": "integer",
"minimum": 1
}
},
{
"name": "limit",
"in": "query",
"schema": {
"type": "integer",
"minimum": 1
}
}
],
"responses": {
"200": {
"description": "Account transactions response",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
},
"/v1/token/metadata": {
"get": {
"operationId": "getTokenMetadata",
"summary": "Get token metadata",
"parameters": [
{
"name": "chain_id",
"in": "query",
"required": true,
"schema": {
"type": "integer"
}
},
{
"name": "contract_address",
"in": "query",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Token metadata response",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
},
"/v1/token/holders": {
"get": {
"operationId": "getTokenHolders",
"summary": "Get token holders",
"parameters": [
{
"name": "chain_id",
"in": "query",
"required": true,
"schema": {
"type": "integer"
}
},
{
"name": "contract_address",
"in": "query",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "page",
"in": "query",
"schema": {
"type": "integer",
"minimum": 1
}
},
{
"name": "limit",
"in": "query",
"schema": {
"type": "integer",
"minimum": 1
}
}
],
"responses": {
"200": {
"description": "Token holders response",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
},
"/v1/token/price": {
"get": {
"operationId": "getTokenPrice",
"summary": "Get token price",
"parameters": [
{
"name": "chain_id",
"in": "query",
"required": true,
"schema": {
"type": "integer"
}
},
{
"name": "contract_address",
"in": "query",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Token price response",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
},
"/v1/tx/detail": {
"get": {
"operationId": "getTransactionDetail",
"summary": "Get transaction detail",
"parameters": [
{
"name": "chain_id",
"in": "query",
"required": true,
"schema": {
"type": "integer"
}
},
{
"name": "tx_hash",
"in": "query",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Transaction detail response",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
}
},
"components": {
"securitySchemes": {
"chainbaseApiKey": {
"type": "apiKey",
"in": "header",
"name": "X-API-KEY"
}
}
}
}
FILE:references/usage-patterns.md
# Chainbase Web3 API Skill - Usage Patterns
## Link Setup
```bash
command -v chainbase-openapi-cli
uxc link chainbase-openapi-cli https://api.chainbase.online \
--schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/chainbase-openapi-skill/references/chainbase-web3.openapi.json
chainbase-openapi-cli -h
```
## Auth Setup
```bash
uxc auth credential set chainbase \
--auth-type api_key \
--api-key-header X-API-KEY \
--secret-env CHAINBASE_API_KEY
uxc auth binding add \
--id chainbase \
--host api.chainbase.online \
--scheme https \
--credential chainbase \
--priority 100
```
Validate the binding:
```bash
uxc auth binding match https://api.chainbase.online
```
## Read Examples
```bash
# Read account native balance
chainbase-openapi-cli get:/v1/account/balance \
chain_id=1 \
address=0xd8da6bf26964af9d7eed9e03e53415d37aa96045
# Read account token balances
chainbase-openapi-cli get:/v1/account/tokens \
chain_id=1 \
address=0xd8da6bf26964af9d7eed9e03e53415d37aa96045 \
page=1 \
limit=20
# Read account transaction history
chainbase-openapi-cli get:/v1/account/txs \
chain_id=1 \
address=0xd8da6bf26964af9d7eed9e03e53415d37aa96045 \
page=1 \
limit=20
# Read token metadata
chainbase-openapi-cli get:/v1/token/metadata \
chain_id=1 \
contract_address=0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
# Read token holders
chainbase-openapi-cli get:/v1/token/holders \
chain_id=1 \
contract_address=0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48 \
page=1 \
limit=20
# Read token price
chainbase-openapi-cli get:/v1/token/price \
chain_id=1 \
contract_address=0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
# Read transaction detail
chainbase-openapi-cli get:/v1/tx/detail \
chain_id=1 \
tx_hash=0x4e3f3bc239f496f59c3e4d4a4d5f10f7f0d6d9f4cd790beeb520d05f6f7d98ae
```
## Fallback Equivalence
- `chainbase-openapi-cli <operation> ...` is equivalent to
`uxc https://api.chainbase.online --schema-url <chainbase_openapi_schema> <operation> ...`.
FILE:scripts/validate.sh
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "BASH_SOURCE[0]")/../../.." && pwd)"
SKILL_DIR="ROOT_DIR/skills/chainbase-openapi-skill"
SKILL_FILE="SKILL_DIR/SKILL.md"
OPENAI_FILE="SKILL_DIR/agents/openai.yaml"
USAGE_FILE="SKILL_DIR/references/usage-patterns.md"
SCHEMA_FILE="SKILL_DIR/references/chainbase-web3.openapi.json"
fail() {
printf '[validate] error: %s\n' "$*" >&2
exit 1
}
need_cmd() {
command -v "$1" >/dev/null 2>&1 || fail "required command not found: $1"
}
need_cmd jq
need_cmd rg
for file in "SKILL_FILE" "OPENAI_FILE" "USAGE_FILE" "SCHEMA_FILE"; do
[[ -f "file" ]] || fail "missing required file: file"
done
jq -e '.openapi and .paths and .components' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'invalid OpenAPI schema JSON or missing .openapi/.paths/.components'
jq -e '.paths["/v1/account/balance"] and .paths["/v1/token/price"]' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'OpenAPI schema missing expected Chainbase paths'
rg -q '^name:\s*chainbase-openapi-skill\s*$' "SKILL_FILE" || fail 'invalid skill name'
rg -q '^description:\s*.+' "SKILL_FILE" || fail 'missing description'
rg -q 'command -v chainbase-openapi-cli' "SKILL_FILE" || fail 'missing link-first command check'
rg -q 'uxc link chainbase-openapi-cli https://api.chainbase.online --schema-url ' "SKILL_FILE" || fail 'missing fixed link create command with schema-url'
rg -F -q 'chainbase-openapi-cli get:/v1/account/balance -h' "SKILL_FILE" || fail 'missing operation-level help example'
rg -q -- '--api-key-header X-API-KEY' "SKILL_FILE" || fail 'missing X-API-KEY auth setup'
rg -q 'uxc auth binding match https://api.chainbase.online' "SKILL_FILE" || fail 'missing binding match check'
rg -q 'read-only' "SKILL_FILE" || fail 'missing read-only guardrail'
if rg -q -- "--args\\s+'\\{" "SKILL_FILE" "USAGE_FILE"; then
fail 'found banned legacy JSON argument pattern'
fi
rg -q '^\s*display_name:\s*"Chainbase Web3 API"\s*$' "OPENAI_FILE" || fail 'missing display_name'
rg -q '^\s*short_description:\s*".+"\s*$' "OPENAI_FILE" || fail 'missing short_description'
rg -q '^\s*default_prompt:\s*".*\$chainbase-openapi-skill.*"\s*$' "OPENAI_FILE" || fail 'default_prompt must mention $chainbase-openapi-skill'
echo "skills/chainbase-openapi-skill validation passed"
Operate Moralis EVM wallet and token reads through UXC with a curated OpenAPI schema, API-key auth, and wallet-intelligence guardrails.
---
name: moralis-openapi-skill
description: Operate Moralis EVM wallet and token reads through UXC with a curated OpenAPI schema, API-key auth, and wallet-intelligence guardrails.
---
# Moralis Web3 Data API Skill
Use this skill to run Moralis EVM data operations through `uxc` + OpenAPI.
Reuse the `uxc` skill for shared execution, auth, and error-handling guidance.
## Prerequisites
- `uxc` is installed and available in `PATH`.
- Network access to `https://deep-index.moralis.io/api/v2.2`.
- Access to the curated OpenAPI schema URL:
- `https://raw.githubusercontent.com/holon-run/uxc/main/skills/moralis-openapi-skill/references/moralis-evm.openapi.json`
- A Moralis API key.
## Scope
This skill covers a read-first wallet intelligence surface:
- native balance lookup
- wallet token balances
- wallet history
- wallet swaps
- wallet net worth
- ERC-20 metadata lookup
- ERC-20 token price lookup
This skill does **not** cover:
- write or transaction submission flows
- Solana, Streams, or NFT-specific surfaces
- the full Moralis API
## Authentication
Moralis uses `X-API-Key` header auth.
Configure one API-key credential and bind it to `deep-index.moralis.io/api/v2.2`:
```bash
uxc auth credential set moralis \
--auth-type api_key \
--api-key-header X-API-Key \
--secret-env MORALIS_API_KEY
uxc auth binding add \
--id moralis \
--host deep-index.moralis.io \
--path-prefix /api/v2.2 \
--scheme https \
--credential moralis \
--priority 100
```
Validate the active mapping when auth looks wrong:
```bash
uxc auth binding match https://deep-index.moralis.io/api/v2.2
```
## Core Workflow
1. Use the fixed link command by default:
- `command -v moralis-openapi-cli`
- If missing, create it:
`uxc link moralis-openapi-cli https://deep-index.moralis.io/api/v2.2 --schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/moralis-openapi-skill/references/moralis-evm.openapi.json`
- `moralis-openapi-cli -h`
2. Inspect operation schema first:
- `moralis-openapi-cli get:/{address}/balance -h`
- `moralis-openapi-cli get:/wallets/{address}/tokens -h`
- `moralis-openapi-cli get:/erc20/{address}/price -h`
3. Prefer narrow reads before broader wallet scans:
- `moralis-openapi-cli get:/{address}/balance address=0xd8da6bf26964af9d7eed9e03e53415d37aa96045 chain=eth`
- `moralis-openapi-cli get:/erc20/{address}/price address=0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48 chain=eth`
- `moralis-openapi-cli get:/wallets/{address}/net-worth address=0xd8da6bf26964af9d7eed9e03e53415d37aa96045 chain=eth`
4. Execute with key/value parameters:
- `moralis-openapi-cli get:/wallets/{address}/tokens address=0xd8da6bf26964af9d7eed9e03e53415d37aa96045 chain=eth`
- `moralis-openapi-cli get:/wallets/{address}/history address=0xd8da6bf26964af9d7eed9e03e53415d37aa96045 chain=eth limit=20`
## Operation Groups
### Wallet Reads
- `get:/{address}/balance`
- `get:/wallets/{address}/tokens`
- `get:/wallets/{address}/history`
- `get:/wallets/{address}/swaps`
- `get:/wallets/{address}/net-worth`
### Token Reads
- `get:/erc20/metadata`
- `get:/erc20/{address}/price`
## Guardrails
- Keep automation on the JSON output envelope; do not use `--text`.
- Parse stable fields first: `ok`, `kind`, `protocol`, `data`, `error`.
- Treat this v1 skill as read-only. Do not imply signing or transaction broadcast support.
- Moralis supports multiple chains. Always pass `chain` explicitly instead of assuming Ethereum.
- Wallet history and swaps can become expensive at large ranges. Start with small limits and narrow time windows.
- `moralis-openapi-cli <operation> ...` is equivalent to `uxc https://deep-index.moralis.io/api/v2.2 --schema-url <moralis_openapi_schema> <operation> ...`.
## References
- Usage patterns: `references/usage-patterns.md`
- Curated OpenAPI schema: `references/moralis-evm.openapi.json`
- Moralis wallet docs: https://docs.moralis.com/data-api/evm/wallet
- Moralis token docs: https://docs.moralis.com/data-api/evm/token
FILE:agents/openai.yaml
interface:
display_name: "Moralis Web3 Data API"
short_description: "Operate Moralis EVM wallet and token reads via UXC + curated OpenAPI schema"
default_prompt: "Use $moralis-openapi-skill to discover and execute Moralis EVM wallet and token read operations through UXC with X-API-Key auth and wallet-intelligence guardrails."
FILE:references/moralis-evm.openapi.json
{
"openapi": "3.0.3",
"info": {
"title": "Moralis EVM Curated API",
"version": "1.0.0",
"description": "Curated read-only Moralis EVM wallet and token surface for UXC."
},
"servers": [
{
"url": "https://deep-index.moralis.io/api/v2.2"
}
],
"security": [
{
"moralisApiKey": []
}
],
"paths": {
"/{address}/balance": {
"get": {
"operationId": "getNativeBalance",
"summary": "Get native balance for a wallet",
"parameters": [
{
"name": "address",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "chain",
"in": "query",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Native balance response",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
},
"/wallets/{address}/tokens": {
"get": {
"operationId": "getWalletTokens",
"summary": "Get token balances for a wallet",
"parameters": [
{
"name": "address",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "chain",
"in": "query",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Wallet tokens response",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
},
"/wallets/{address}/history": {
"get": {
"operationId": "getWalletHistory",
"summary": "Get wallet history",
"parameters": [
{
"name": "address",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "chain",
"in": "query",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "limit",
"in": "query",
"schema": {
"type": "integer",
"minimum": 1
}
},
{
"name": "cursor",
"in": "query",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Wallet history response",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
},
"/wallets/{address}/swaps": {
"get": {
"operationId": "getWalletSwaps",
"summary": "Get wallet swaps",
"parameters": [
{
"name": "address",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "chain",
"in": "query",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "limit",
"in": "query",
"schema": {
"type": "integer",
"minimum": 1
}
},
{
"name": "cursor",
"in": "query",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Wallet swaps response",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
},
"/wallets/{address}/net-worth": {
"get": {
"operationId": "getWalletNetWorth",
"summary": "Get wallet net worth",
"parameters": [
{
"name": "address",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "chain",
"in": "query",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Wallet net worth response",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
},
"/erc20/metadata": {
"get": {
"operationId": "getErc20Metadata",
"summary": "Get ERC-20 metadata",
"parameters": [
{
"name": "chain",
"in": "query",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "addresses",
"in": "query",
"required": true,
"schema": {
"type": "string"
},
"description": "Comma-separated token contract addresses."
}
],
"responses": {
"200": {
"description": "ERC-20 metadata response",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
}
},
"/erc20/{address}/price": {
"get": {
"operationId": "getErc20Price",
"summary": "Get ERC-20 token price",
"parameters": [
{
"name": "address",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "chain",
"in": "query",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "ERC-20 price response",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
}
},
"components": {
"securitySchemes": {
"moralisApiKey": {
"type": "apiKey",
"in": "header",
"name": "X-API-Key"
}
}
}
}
FILE:references/usage-patterns.md
# Moralis Web3 Data API Skill - Usage Patterns
## Link Setup
```bash
command -v moralis-openapi-cli
uxc link moralis-openapi-cli https://deep-index.moralis.io/api/v2.2 \
--schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/moralis-openapi-skill/references/moralis-evm.openapi.json
moralis-openapi-cli -h
```
## Auth Setup
```bash
uxc auth credential set moralis \
--auth-type api_key \
--api-key-header X-API-Key \
--secret-env MORALIS_API_KEY
uxc auth binding add \
--id moralis \
--host deep-index.moralis.io \
--path-prefix /api/v2.2 \
--scheme https \
--credential moralis \
--priority 100
```
Validate the binding:
```bash
uxc auth binding match https://deep-index.moralis.io/api/v2.2
```
## Read Examples
```bash
# Read native balance
moralis-openapi-cli get:/{address}/balance \
address=0xd8da6bf26964af9d7eed9e03e53415d37aa96045 \
chain=eth
# Read wallet token balances
moralis-openapi-cli get:/wallets/{address}/tokens \
address=0xd8da6bf26964af9d7eed9e03e53415d37aa96045 \
chain=eth
# Read wallet history
moralis-openapi-cli get:/wallets/{address}/history \
address=0xd8da6bf26964af9d7eed9e03e53415d37aa96045 \
chain=eth \
limit=20
# Read wallet swaps
moralis-openapi-cli get:/wallets/{address}/swaps \
address=0xd8da6bf26964af9d7eed9e03e53415d37aa96045 \
chain=eth \
limit=20
# Read wallet net worth
moralis-openapi-cli get:/wallets/{address}/net-worth \
address=0xd8da6bf26964af9d7eed9e03e53415d37aa96045 \
chain=eth
# Read ERC-20 metadata
moralis-openapi-cli get:/erc20/metadata \
chain=eth \
addresses=0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
# Read ERC-20 token price
moralis-openapi-cli get:/erc20/{address}/price \
address=0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48 \
chain=eth
```
## Fallback Equivalence
- `moralis-openapi-cli <operation> ...` is equivalent to
`uxc https://deep-index.moralis.io/api/v2.2 --schema-url <moralis_openapi_schema> <operation> ...`.
FILE:scripts/validate.sh
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "BASH_SOURCE[0]")/../../.." && pwd)"
SKILL_DIR="ROOT_DIR/skills/moralis-openapi-skill"
SKILL_FILE="SKILL_DIR/SKILL.md"
OPENAI_FILE="SKILL_DIR/agents/openai.yaml"
USAGE_FILE="SKILL_DIR/references/usage-patterns.md"
SCHEMA_FILE="SKILL_DIR/references/moralis-evm.openapi.json"
fail() {
printf '[validate] error: %s\n' "$*" >&2
exit 1
}
need_cmd() {
command -v "$1" >/dev/null 2>&1 || fail "required command not found: $1"
}
need_cmd jq
need_cmd rg
for file in "SKILL_FILE" "OPENAI_FILE" "USAGE_FILE" "SCHEMA_FILE"; do
[[ -f "file" ]] || fail "missing required file: file"
done
jq -e '.openapi and .paths and .components' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'invalid OpenAPI schema JSON or missing .openapi/.paths/.components'
jq -e '.paths["/{address}/balance"] and .paths["/erc20/{address}/price"]' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'OpenAPI schema missing expected Moralis paths'
rg -q '^name:\s*moralis-openapi-skill\s*$' "SKILL_FILE" || fail 'invalid skill name'
rg -q '^description:\s*.+' "SKILL_FILE" || fail 'missing description'
rg -q 'command -v moralis-openapi-cli' "SKILL_FILE" || fail 'missing link-first command check'
rg -q 'uxc link moralis-openapi-cli https://deep-index.moralis.io/api/v2.2 --schema-url ' "SKILL_FILE" || fail 'missing fixed link create command with schema-url'
rg -F -q 'moralis-openapi-cli get:/{address}/balance -h' "SKILL_FILE" || fail 'missing operation-level help example'
rg -q -- '--api-key-header X-API-Key' "SKILL_FILE" || fail 'missing X-API-Key auth setup'
rg -q 'uxc auth binding match https://deep-index.moralis.io/api/v2.2' "SKILL_FILE" || fail 'missing binding match check'
rg -q 'read-only' "SKILL_FILE" || fail 'missing read-only guardrail'
if rg -q -- "--args\\s+'\\{" "SKILL_FILE" "USAGE_FILE"; then
fail 'found banned legacy JSON argument pattern'
fi
rg -q '^\s*display_name:\s*"Moralis Web3 Data API"\s*$' "OPENAI_FILE" || fail 'missing display_name'
rg -q '^\s*short_description:\s*".+"\s*$' "OPENAI_FILE" || fail 'missing short_description'
rg -q '^\s*default_prompt:\s*".*\$moralis-openapi-skill.*"\s*$' "OPENAI_FILE" || fail 'default_prompt must mention $moralis-openapi-skill'
echo "skills/moralis-openapi-skill validation passed"
Operate Upbit public exchange market APIs through UXC with a curated OpenAPI schema, market-first discovery, and explicit private-auth boundary notes.
---
name: upbit-openapi-skill
description: Operate Upbit public exchange market APIs through UXC with a curated OpenAPI schema, market-first discovery, and explicit private-auth boundary notes.
---
# Upbit Open API Skill
Use this skill to run Upbit public market-data operations through `uxc` + OpenAPI.
Reuse the `uxc` skill for shared execution, auth, and error-handling guidance.
## Prerequisites
- `uxc` is installed and available in `PATH`.
- Network access to the chosen Upbit regional API host.
- Access to the curated OpenAPI schema URL:
- `https://raw.githubusercontent.com/holon-run/uxc/main/skills/upbit-openapi-skill/references/upbit-public.openapi.json`
## Scope
This skill covers a curated Upbit public surface for:
- market discovery
- ticker reads
- minute candles
- order book snapshots
This skill does **not** cover:
- private account or order endpoints in v1
- region-specific account/trade auth flows
## Endpoint
Upbit uses regional hosts. Pick the right one for the market you need before linking.
Examples:
- `https://sg-api.upbit.com`
- `https://id-api.upbit.com`
- `https://th-api.upbit.com`
## Authentication
Public market endpoints in this skill do not require credentials.
Upbit private APIs use provider-specific bearer JWT generation with request-specific claims. Keep this v1 skill public-data-only until a reusable Upbit signer flow exists in `uxc`.
## Core Workflow
1. Choose the correct regional host for the market you need.
2. Use a fixed link command by default:
- `command -v upbit-openapi-cli`
- If missing, create it:
`uxc link upbit-openapi-cli https://sg-api.upbit.com --schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/upbit-openapi-skill/references/upbit-public.openapi.json`
- `upbit-openapi-cli -h`
3. Inspect operation help before execution:
- `upbit-openapi-cli get:/v1/market/all -h`
- `upbit-openapi-cli get:/v1/ticker -h`
4. Prefer narrow market reads first:
- `upbit-openapi-cli get:/v1/ticker markets=SGD-BTC`
- `upbit-openapi-cli get:/v1/orderbook markets=SGD-BTC`
## Operations
- `get:/v1/market/all`
- `get:/v1/ticker`
- `get:/v1/candles/minutes/{unit}`
- `get:/v1/orderbook`
## Guardrails
- Keep automation on the JSON output envelope; do not use `--text`.
- Parse stable fields first: `ok`, `kind`, `protocol`, `data`, `error`.
- Treat this v1 skill as read-only.
- Confirm the correct regional host and quote market before execution.
- On regional Upbit hosts, live market codes are quote-first, for example `SGD-BTC` and `USDT-BTC`.
- `upbit-openapi-cli <operation> ...` is equivalent to `uxc <upbit_region_host> --schema-url <upbit_public_openapi_schema> <operation> ...`.
## References
- Usage patterns: `references/usage-patterns.md`
- Curated OpenAPI schema: `references/upbit-public.openapi.json`
- Official Upbit Open API overview: https://global-docs.upbit.com/reference/api-overview
FILE:agents/openai.yaml
interface:
display_name: "Upbit Open API"
short_description: "Upbit public market data via curated regional REST endpoints"
default_prompt: "Use $upbit-openapi-skill to discover and execute Upbit public market-data operations through UXC with help-first schema inspection, region-aware host selection, and explicit private-auth boundary notes."
FILE:references/upbit-public.openapi.json
{
"openapi": "3.0.3",
"info": {
"title": "Upbit Public API",
"version": "v1",
"description": "Curated Upbit public market-data surface for UXC."
},
"servers": [
{ "url": "https://sg-api.upbit.com" }
],
"components": {
"schemas": {}
},
"paths": {
"/v1/market/all": {
"get": {
"operationId": "listMarkets",
"parameters": [
{ "name": "isDetails", "in": "query", "schema": { "type": "boolean" } }
],
"responses": { "200": { "description": "Markets returned" } }
}
},
"/v1/ticker": {
"get": {
"operationId": "getTicker",
"parameters": [
{ "name": "markets", "in": "query", "required": true, "schema": { "type": "string" } }
],
"responses": { "200": { "description": "Ticker returned" } }
}
},
"/v1/candles/minutes/{unit}": {
"get": {
"operationId": "getMinuteCandles",
"parameters": [
{ "name": "unit", "in": "path", "required": true, "schema": { "type": "integer" } },
{ "name": "market", "in": "query", "required": true, "schema": { "type": "string" } },
{ "name": "count", "in": "query", "schema": { "type": "integer" } },
{ "name": "to", "in": "query", "schema": { "type": "string" } }
],
"responses": { "200": { "description": "Minute candles returned" } }
}
},
"/v1/orderbook": {
"get": {
"operationId": "getOrderbook",
"parameters": [
{ "name": "markets", "in": "query", "required": true, "schema": { "type": "string" } }
],
"responses": { "200": { "description": "Orderbook returned" } }
}
}
}
}
FILE:references/usage-patterns.md
# Upbit Open API Skill - Usage Patterns
## Link Setup
Choose the right regional host first. Example for Singapore:
```bash
command -v upbit-openapi-cli
uxc link upbit-openapi-cli https://sg-api.upbit.com \
--schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/upbit-openapi-skill/references/upbit-public.openapi.json
upbit-openapi-cli -h
```
## Read Examples
```bash
# List markets
upbit-openapi-cli get:/v1/market/all isDetails=false
# Read ticker
upbit-openapi-cli get:/v1/ticker markets=SGD-BTC
# Read minute candles
upbit-openapi-cli get:/v1/candles/minutes/{unit} unit=60 market=SGD-BTC count=24
# Read order book
upbit-openapi-cli get:/v1/orderbook markets=SGD-BTC
```
## Guardrail Note
- Keep this v1 skill on public reads only because Upbit private APIs use provider-specific JWT generation with request-specific claims not yet packaged into a reusable `uxc` signer flow.
- Live Upbit market codes are quote-first on regional hosts, for example `SGD-BTC`.
## Fallback Equivalence
- `upbit-openapi-cli <operation> ...` is equivalent to
`uxc <upbit_region_host> --schema-url <upbit_public_openapi_schema> <operation> ...`.
FILE:scripts/validate.sh
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "BASH_SOURCE[0]")/../../.." && pwd)"
SKILL_DIR="ROOT_DIR/skills/upbit-openapi-skill"
SKILL_FILE="SKILL_DIR/SKILL.md"
OPENAI_FILE="SKILL_DIR/agents/openai.yaml"
USAGE_FILE="SKILL_DIR/references/usage-patterns.md"
SCHEMA_FILE="SKILL_DIR/references/upbit-public.openapi.json"
fail() {
printf '[validate] error: %s\n' "$*" >&2
exit 1
}
need_cmd() {
command -v "$1" >/dev/null 2>&1 || fail "required command not found: $1"
}
need_cmd jq
need_cmd rg
for file in "SKILL_FILE" "OPENAI_FILE" "USAGE_FILE" "SCHEMA_FILE"; do
[[ -f "file" ]] || fail "missing required file: file"
done
jq -e '.openapi and .paths and .components' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'invalid OpenAPI schema JSON or missing .openapi/.paths/.components'
jq -e '.paths["/v1/market/all"] and .paths["/v1/ticker"]' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'OpenAPI schema missing expected Upbit paths'
rg -q '^name:\s*upbit-openapi-skill\s*$' "SKILL_FILE" || fail 'invalid skill name'
rg -q 'command -v upbit-openapi-cli' "SKILL_FILE" || fail 'missing link-first command check'
rg -q 'uxc link upbit-openapi-cli https://sg-api.upbit.com --schema-url ' "SKILL_FILE" || fail 'missing fixed link create command with schema-url'
rg -q 'request-specific claims' "SKILL_FILE" "USAGE_FILE" || fail 'missing private auth boundary note'
rg -q 'read-only' "SKILL_FILE" || fail 'missing read-only guardrail'
rg -q '^\s*display_name:\s*"Upbit Open API"\s*$' "OPENAI_FILE" || fail 'missing display_name'
rg -q '^\s*default_prompt:\s*".*\$upbit-openapi-skill.*"\s*$' "OPENAI_FILE" || fail 'default_prompt must mention $upbit-openapi-skill'
echo "skills/upbit-openapi-skill validation passed"
Operate Bitget public exchange market APIs through UXC with a curated OpenAPI schema, market-first discovery, and explicit private-auth boundary notes.
---
name: bitget-openapi-skill
description: Operate Bitget public exchange market APIs through UXC with a curated OpenAPI schema, market-first discovery, and explicit private-auth boundary notes.
---
# Bitget Exchange Skill
Use this skill to run Bitget public market-data operations through `uxc` + OpenAPI.
Reuse the `uxc` skill for shared execution, auth, and error-handling guidance.
## Prerequisites
- `uxc` is installed and available in `PATH`.
- Network access to `https://api.bitget.com`.
- Access to the curated OpenAPI schema URL:
- `https://raw.githubusercontent.com/holon-run/uxc/main/skills/bitget-openapi-skill/references/bitget-v2.openapi.json`
## Scope
This skill covers a curated Bitget public market surface for:
- spot symbols and metadata
- ticker reads
- candlestick reads
- order book snapshots
This skill does **not** cover:
- private account endpoints in v1
- private order placement or cancellation in v1
- copy trading or P2P workflows
## Authentication
Public market endpoints in this skill do not require credentials.
Bitget private APIs use provider-specific header signing and timestamp headers. Keep this v1 skill public-data-only until a reusable Bitget signer flow exists in `uxc`.
## Core Workflow
1. Use the fixed link command by default:
- `command -v bitget-openapi-cli`
- If missing, create it:
`uxc link bitget-openapi-cli https://api.bitget.com --schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/bitget-openapi-skill/references/bitget-v2.openapi.json`
- `bitget-openapi-cli -h`
2. Inspect operation help before execution:
- `bitget-openapi-cli get:/api/v2/spot/public/symbols -h`
- `bitget-openapi-cli get:/api/v2/spot/market/tickers -h`
3. Prefer narrow spot reads first:
- `bitget-openapi-cli get:/api/v2/spot/market/tickers symbol=BTCUSDT`
- `bitget-openapi-cli get:/api/v2/spot/market/orderbook symbol=BTCUSDT limit=20`
## Operations
- `get:/api/v2/spot/public/symbols`
- `get:/api/v2/spot/market/tickers`
- `get:/api/v2/spot/market/candles`
- `get:/api/v2/spot/market/orderbook`
## Guardrails
- Keep automation on the JSON output envelope; do not use `--text`.
- Parse stable fields first: `ok`, `kind`, `protocol`, `data`, `error`.
- Treat this v1 skill as read-only.
- Keep symbol and candle ranges narrow unless the user explicitly wants a broader pull.
- `bitget-openapi-cli <operation> ...` is equivalent to `uxc https://api.bitget.com --schema-url <bitget_v2_openapi_schema> <operation> ...`.
## References
- Usage patterns: `references/usage-patterns.md`
- Curated OpenAPI schema: `references/bitget-v2.openapi.json`
- Official Bitget API intro: https://www.bitget.com/api-doc/common/intro
FILE:agents/openai.yaml
interface:
display_name: "Bitget Exchange"
short_description: "Bitget public spot market data via curated V2 REST endpoints"
default_prompt: "Use $bitget-openapi-skill to discover and execute Bitget public spot market-data operations through UXC with help-first schema inspection, narrow symbol reads, and explicit private-auth boundary notes."
FILE:references/bitget-v2.openapi.json
{
"openapi": "3.0.3",
"info": {
"title": "Bitget Spot API",
"version": "v2",
"description": "Curated Bitget V2 public spot market surface for UXC."
},
"servers": [
{ "url": "https://api.bitget.com" }
],
"components": {
"schemas": {}
},
"paths": {
"/api/v2/spot/public/symbols": {
"get": {
"operationId": "listSymbols",
"parameters": [
{ "name": "symbol", "in": "query", "schema": { "type": "string" } }
],
"responses": { "200": { "description": "Symbols returned" } }
}
},
"/api/v2/spot/market/tickers": {
"get": {
"operationId": "getTickers",
"parameters": [
{ "name": "symbol", "in": "query", "schema": { "type": "string" } }
],
"responses": { "200": { "description": "Tickers returned" } }
}
},
"/api/v2/spot/market/candles": {
"get": {
"operationId": "getCandles",
"parameters": [
{ "name": "symbol", "in": "query", "required": true, "schema": { "type": "string" } },
{ "name": "granularity", "in": "query", "required": true, "schema": { "type": "string" } },
{ "name": "startTime", "in": "query", "schema": { "type": "integer" } },
{ "name": "endTime", "in": "query", "schema": { "type": "integer" } },
{ "name": "limit", "in": "query", "schema": { "type": "integer" } }
],
"responses": { "200": { "description": "Candles returned" } }
}
},
"/api/v2/spot/market/orderbook": {
"get": {
"operationId": "getOrderbook",
"parameters": [
{ "name": "symbol", "in": "query", "required": true, "schema": { "type": "string" } },
{ "name": "limit", "in": "query", "schema": { "type": "integer" } }
],
"responses": { "200": { "description": "Orderbook returned" } }
}
}
}
}
FILE:references/usage-patterns.md
# Bitget Exchange Skill - Usage Patterns
## Link Setup
```bash
command -v bitget-openapi-cli
uxc link bitget-openapi-cli https://api.bitget.com \
--schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/bitget-openapi-skill/references/bitget-v2.openapi.json
bitget-openapi-cli -h
```
## Read Examples
```bash
# Read spot symbol metadata
bitget-openapi-cli get:/api/v2/spot/public/symbols symbol=BTCUSDT
# Read spot ticker
bitget-openapi-cli get:/api/v2/spot/market/tickers symbol=BTCUSDT
# Read spot candles
bitget-openapi-cli get:/api/v2/spot/market/candles symbol=BTCUSDT granularity=1h limit=24
# Read spot order book
bitget-openapi-cli get:/api/v2/spot/market/orderbook symbol=BTCUSDT limit=20
```
## Guardrail Note
- Keep this v1 skill on public reads only because Bitget private REST auth uses provider-specific header signing not yet packaged into a reusable `uxc` signer flow.
## Fallback Equivalence
- `bitget-openapi-cli <operation> ...` is equivalent to
`uxc https://api.bitget.com --schema-url <bitget_v2_openapi_schema> <operation> ...`.
FILE:scripts/validate.sh
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "BASH_SOURCE[0]")/../../.." && pwd)"
SKILL_DIR="ROOT_DIR/skills/bitget-openapi-skill"
SKILL_FILE="SKILL_DIR/SKILL.md"
OPENAI_FILE="SKILL_DIR/agents/openai.yaml"
USAGE_FILE="SKILL_DIR/references/usage-patterns.md"
SCHEMA_FILE="SKILL_DIR/references/bitget-v2.openapi.json"
fail() {
printf '[validate] error: %s\n' "$*" >&2
exit 1
}
need_cmd() {
command -v "$1" >/dev/null 2>&1 || fail "required command not found: $1"
}
need_cmd jq
need_cmd rg
for file in "SKILL_FILE" "OPENAI_FILE" "USAGE_FILE" "SCHEMA_FILE"; do
[[ -f "file" ]] || fail "missing required file: file"
done
jq -e '.openapi and .paths and .components' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'invalid OpenAPI schema JSON or missing .openapi/.paths/.components'
jq -e '.paths["/api/v2/spot/public/symbols"] and .paths["/api/v2/spot/market/tickers"]' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'OpenAPI schema missing expected Bitget paths'
rg -q '^name:\s*bitget-openapi-skill\s*$' "SKILL_FILE" || fail 'invalid skill name'
rg -q 'command -v bitget-openapi-cli' "SKILL_FILE" || fail 'missing link-first command check'
rg -q 'uxc link bitget-openapi-cli https://api.bitget.com --schema-url ' "SKILL_FILE" || fail 'missing fixed link create command with schema-url'
rg -q 'provider-specific header signing' "SKILL_FILE" "USAGE_FILE" || fail 'missing private auth boundary note'
rg -q 'read-only' "SKILL_FILE" || fail 'missing read-only guardrail'
if rg -q -- "--args\\s+'\\{" "SKILL_FILE" "USAGE_FILE"; then
fail 'found banned legacy JSON argument pattern'
fi
rg -q '^\s*display_name:\s*"Bitget Exchange"\s*$' "OPENAI_FILE" || fail 'missing display_name'
rg -q '^\s*short_description:\s*".+"\s*$' "OPENAI_FILE" || fail 'missing short_description'
rg -q '^\s*default_prompt:\s*".*\$bitget-openapi-skill.*"\s*$' "OPENAI_FILE" || fail 'default_prompt must mention $bitget-openapi-skill'
echo "skills/bitget-openapi-skill validation passed"
Operate Bybit V5 public market APIs through UXC with a curated OpenAPI schema, market-first discovery, and explicit private-auth boundary notes.
---
name: bybit-openapi-skill
description: Operate Bybit V5 public market APIs through UXC with a curated OpenAPI schema, market-first discovery, and explicit private-auth boundary notes.
---
# Bybit V5 Skill
Use this skill to run Bybit V5 market-data operations through `uxc` + OpenAPI.
Reuse the `uxc` skill for shared execution, auth, and error-handling guidance.
## Prerequisites
- `uxc` is installed and available in `PATH`.
- Network access to:
- `https://api.bybit.com`
- optionally `https://api-testnet.bybit.com`
- Access to the curated OpenAPI schema URL:
- `https://raw.githubusercontent.com/holon-run/uxc/main/skills/bybit-openapi-skill/references/bybit-v5.openapi.json`
## Scope
This skill covers a curated Bybit V5 public market surface for:
- server time
- instruments metadata
- tickers
- order book snapshots
- kline reads
This skill does **not** cover:
- private account endpoints in v1
- private order placement or cancellation in v1
- copy trading, earn, broker, or asset management product families
## Authentication
Public market endpoints in this skill do not require credentials.
Bybit private APIs use provider-specific header signing that is not yet packaged as a generic `uxc` signer flow. Keep this v1 skill public-data-only until a reusable Bybit signer path exists.
## Region Guardrail
Bybit's official docs note region and IP restrictions. If requests fail unexpectedly, verify that the current execution environment is permitted for Bybit API access before debugging the schema or parameters.
## Core Workflow
1. Use the fixed link command by default:
- `command -v bybit-openapi-cli`
- If missing, create it:
`uxc link bybit-openapi-cli https://api.bybit.com --schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/bybit-openapi-skill/references/bybit-v5.openapi.json`
- `bybit-openapi-cli -h`
2. Inspect operation help before execution:
- `bybit-openapi-cli get:/v5/market/time -h`
- `bybit-openapi-cli get:/v5/market/instruments-info -h`
- `bybit-openapi-cli get:/v5/market/tickers -h`
3. Prefer narrow spot reads first:
- `bybit-openapi-cli get:/v5/market/tickers category=spot symbol=BTCUSDT`
- `bybit-openapi-cli get:/v5/market/orderbook category=spot symbol=BTCUSDT limit=20`
## Operations
- `get:/v5/market/time`
- `get:/v5/market/instruments-info`
- `get:/v5/market/tickers`
- `get:/v5/market/orderbook`
- `get:/v5/market/kline`
## Guardrails
- Keep automation on the JSON output envelope; do not use `--text`.
- Parse stable fields first: `ok`, `kind`, `protocol`, `data`, `error`.
- Treat this v1 skill as read-only.
- Use `category=spot` unless the user explicitly needs another market family and has checked the symbol format.
- `bybit-openapi-cli <operation> ...` is equivalent to `uxc https://api.bybit.com --schema-url <bybit_v5_openapi_schema> <operation> ...`.
## References
- Usage patterns: `references/usage-patterns.md`
- Curated OpenAPI schema: `references/bybit-v5.openapi.json`
- Official Bybit V5 docs: https://bybit-exchange.github.io/docs/v5/guide
FILE:agents/openai.yaml
interface:
display_name: "Bybit V5"
short_description: "Bybit public market data via the V5 REST API through UXC"
default_prompt: "Use $bybit-openapi-skill to discover and execute Bybit V5 public market-data operations through UXC with help-first schema inspection, narrow symbol reads, and explicit private-auth boundary notes."
FILE:references/bybit-v5.openapi.json
{
"openapi": "3.0.3",
"info": {
"title": "Bybit V5 API",
"version": "v1",
"description": "Curated Bybit V5 public market surface for UXC."
},
"servers": [
{
"url": "https://api.bybit.com"
}
],
"components": {
"schemas": {}
},
"paths": {
"/v5/market/time": {
"get": {
"operationId": "getServerTime",
"responses": { "200": { "description": "Server time returned" } }
}
},
"/v5/market/instruments-info": {
"get": {
"operationId": "listInstruments",
"parameters": [
{ "name": "category", "in": "query", "required": true, "schema": { "type": "string" } },
{ "name": "symbol", "in": "query", "schema": { "type": "string" } },
{ "name": "limit", "in": "query", "schema": { "type": "integer" } }
],
"responses": { "200": { "description": "Instrument metadata returned" } }
}
},
"/v5/market/tickers": {
"get": {
"operationId": "getTickers",
"parameters": [
{ "name": "category", "in": "query", "required": true, "schema": { "type": "string" } },
{ "name": "symbol", "in": "query", "schema": { "type": "string" } },
{ "name": "baseCoin", "in": "query", "schema": { "type": "string" } }
],
"responses": { "200": { "description": "Tickers returned" } }
}
},
"/v5/market/orderbook": {
"get": {
"operationId": "getOrderbook",
"parameters": [
{ "name": "category", "in": "query", "required": true, "schema": { "type": "string" } },
{ "name": "symbol", "in": "query", "required": true, "schema": { "type": "string" } },
{ "name": "limit", "in": "query", "schema": { "type": "integer" } }
],
"responses": { "200": { "description": "Order book returned" } }
}
},
"/v5/market/kline": {
"get": {
"operationId": "getKlines",
"parameters": [
{ "name": "category", "in": "query", "required": true, "schema": { "type": "string" } },
{ "name": "symbol", "in": "query", "required": true, "schema": { "type": "string" } },
{ "name": "interval", "in": "query", "required": true, "schema": { "type": "string" } },
{ "name": "start", "in": "query", "schema": { "type": "integer" } },
{ "name": "end", "in": "query", "schema": { "type": "integer" } },
{ "name": "limit", "in": "query", "schema": { "type": "integer" } }
],
"responses": { "200": { "description": "Klines returned" } }
}
}
}
}
FILE:references/usage-patterns.md
# Bybit V5 Skill - Usage Patterns
## Link Setup
```bash
command -v bybit-openapi-cli
uxc link bybit-openapi-cli https://api.bybit.com \
--schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/bybit-openapi-skill/references/bybit-v5.openapi.json
bybit-openapi-cli -h
```
## Read Examples
```bash
# Read Bybit server time
bybit-openapi-cli get:/v5/market/time
# Read spot instrument metadata
bybit-openapi-cli get:/v5/market/instruments-info category=spot symbol=BTCUSDT
# Read spot ticker
bybit-openapi-cli get:/v5/market/tickers category=spot symbol=BTCUSDT
# Read spot order book snapshot
bybit-openapi-cli get:/v5/market/orderbook category=spot symbol=BTCUSDT limit=20
# Read spot kline data
bybit-openapi-cli get:/v5/market/kline category=spot symbol=BTCUSDT interval=60 limit=24
```
## Guardrail Note
- Keep this v1 skill on public reads only because Bybit private REST auth uses provider-specific header signing not yet packaged into a reusable `uxc` signer flow.
## Fallback Equivalence
- `bybit-openapi-cli <operation> ...` is equivalent to
`uxc https://api.bybit.com --schema-url <bybit_v5_openapi_schema> <operation> ...`.
FILE:scripts/validate.sh
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "BASH_SOURCE[0]")/../../.." && pwd)"
SKILL_DIR="ROOT_DIR/skills/bybit-openapi-skill"
SKILL_FILE="SKILL_DIR/SKILL.md"
OPENAI_FILE="SKILL_DIR/agents/openai.yaml"
USAGE_FILE="SKILL_DIR/references/usage-patterns.md"
SCHEMA_FILE="SKILL_DIR/references/bybit-v5.openapi.json"
fail() {
printf '[validate] error: %s\n' "$*" >&2
exit 1
}
need_cmd() {
command -v "$1" >/dev/null 2>&1 || fail "required command not found: $1"
}
need_cmd jq
need_cmd rg
for file in "SKILL_FILE" "OPENAI_FILE" "USAGE_FILE" "SCHEMA_FILE"; do
[[ -f "file" ]] || fail "missing required file: file"
done
jq -e '.openapi and .paths and .components' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'invalid OpenAPI schema JSON or missing .openapi/.paths/.components'
jq -e '.paths["/v5/market/time"] and .paths["/v5/market/tickers"]' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'OpenAPI schema missing expected Bybit paths'
rg -q '^name:\s*bybit-openapi-skill\s*$' "SKILL_FILE" || fail 'invalid skill name'
rg -q '^description:\s*.+' "SKILL_FILE" || fail 'missing description'
rg -q 'command -v bybit-openapi-cli' "SKILL_FILE" || fail 'missing link-first command check'
rg -q 'uxc link bybit-openapi-cli https://api.bybit.com --schema-url ' "SKILL_FILE" || fail 'missing fixed link create command with schema-url'
rg -q 'bybit-openapi-cli get:/v5/market/time -h' "SKILL_FILE" || fail 'missing operation-level help example'
rg -q 'provider-specific header signing' "SKILL_FILE" "USAGE_FILE" || fail 'missing private auth boundary note'
rg -q 'read-only' "SKILL_FILE" || fail 'missing read-only guardrail'
if rg -q -- "--args\\s+'\\{" "SKILL_FILE" "USAGE_FILE"; then
fail 'found banned legacy JSON argument pattern'
fi
rg -q '^\s*display_name:\s*"Bybit V5"\s*$' "OPENAI_FILE" || fail 'missing display_name'
rg -q '^\s*short_description:\s*".+"\s*$' "OPENAI_FILE" || fail 'missing short_description'
rg -q '^\s*default_prompt:\s*".*\$bybit-openapi-skill.*"\s*$' "OPENAI_FILE" || fail 'default_prompt must mention $bybit-openapi-skill'
echo "skills/bybit-openapi-skill validation passed"
Operate Kraken public market APIs through UXC with a curated OpenAPI schema, market-first discovery, and explicit private-auth boundary notes.
---
name: kraken-openapi-skill
description: Operate Kraken public market APIs through UXC with a curated OpenAPI schema, market-first discovery, and explicit private-auth boundary notes.
---
# Kraken REST Skill
Use this skill to run Kraken public market-data operations through `uxc` + OpenAPI.
Reuse the `uxc` skill for shared execution, auth, and error-handling guidance.
## Prerequisites
- `uxc` is installed and available in `PATH`.
- Network access to `https://api.kraken.com`.
- Access to the curated OpenAPI schema URL:
- `https://raw.githubusercontent.com/holon-run/uxc/main/skills/kraken-openapi-skill/references/kraken-public.openapi.json`
## Scope
This skill covers a curated Kraken public surface for:
- server time
- asset pair metadata
- ticker reads
- OHLC candles
- order book snapshots
This skill does **not** cover:
- private account or trade endpoints in v1
- Kraken FIX
- broader non-core platform products
## Authentication
Public market endpoints in this skill do not require credentials.
Kraken private REST endpoints use provider-specific header signing and nonce handling. Keep this v1 skill public-data-only until a reusable Kraken signer flow exists in `uxc`.
## Core Workflow
1. Use the fixed link command by default:
- `command -v kraken-openapi-cli`
- If missing, create it:
`uxc link kraken-openapi-cli https://api.kraken.com --schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/kraken-openapi-skill/references/kraken-public.openapi.json`
- `kraken-openapi-cli -h`
2. Inspect operation help before execution:
- `kraken-openapi-cli get:/0/public/Time -h`
- `kraken-openapi-cli get:/0/public/Ticker -h`
3. Prefer narrow pair reads first:
- `kraken-openapi-cli get:/0/public/Ticker pair=XBTUSD`
- `kraken-openapi-cli get:/0/public/Depth pair=XBTUSD count=20`
## Operations
- `get:/0/public/Time`
- `get:/0/public/AssetPairs`
- `get:/0/public/Ticker`
- `get:/0/public/OHLC`
- `get:/0/public/Depth`
## Guardrails
- Keep automation on the JSON output envelope; do not use `--text`.
- Parse stable fields first: `ok`, `kind`, `protocol`, `data`, `error`.
- Treat this v1 skill as read-only.
- Kraken pair naming can differ from other venues. Check `AssetPairs` before assuming symbol strings.
- `kraken-openapi-cli <operation> ...` is equivalent to `uxc https://api.kraken.com --schema-url <kraken_public_openapi_schema> <operation> ...`.
## References
- Usage patterns: `references/usage-patterns.md`
- Curated OpenAPI schema: `references/kraken-public.openapi.json`
- Official Kraken API intro: https://docs.kraken.com/api/docs/guides/global-intro
FILE:agents/openai.yaml
interface:
display_name: "Kraken REST"
short_description: "Kraken public market data via curated REST endpoints"
default_prompt: "Use $kraken-openapi-skill to discover and execute Kraken public market-data operations through UXC with help-first schema inspection, pair-aware reads, and explicit private-auth boundary notes."
FILE:references/kraken-public.openapi.json
{
"openapi": "3.0.3",
"info": {
"title": "Kraken Public API",
"version": "v1",
"description": "Curated Kraken public market-data surface for UXC."
},
"servers": [
{ "url": "https://api.kraken.com" }
],
"components": {
"schemas": {}
},
"paths": {
"/0/public/Time": {
"get": {
"operationId": "getServerTime",
"responses": { "200": { "description": "Server time returned" } }
}
},
"/0/public/AssetPairs": {
"get": {
"operationId": "listAssetPairs",
"parameters": [
{ "name": "pair", "in": "query", "schema": { "type": "string" } }
],
"responses": { "200": { "description": "Asset pairs returned" } }
}
},
"/0/public/Ticker": {
"get": {
"operationId": "getTicker",
"parameters": [
{ "name": "pair", "in": "query", "required": true, "schema": { "type": "string" } }
],
"responses": { "200": { "description": "Ticker returned" } }
}
},
"/0/public/OHLC": {
"get": {
"operationId": "getOhlc",
"parameters": [
{ "name": "pair", "in": "query", "required": true, "schema": { "type": "string" } },
{ "name": "interval", "in": "query", "schema": { "type": "integer" } },
{ "name": "since", "in": "query", "schema": { "type": "integer" } }
],
"responses": { "200": { "description": "OHLC returned" } }
}
},
"/0/public/Depth": {
"get": {
"operationId": "getDepth",
"parameters": [
{ "name": "pair", "in": "query", "required": true, "schema": { "type": "string" } },
{ "name": "count", "in": "query", "schema": { "type": "integer" } }
],
"responses": { "200": { "description": "Depth returned" } }
}
}
}
}
FILE:references/kraken-spot-futures.openapi.json
{
"openapi": "3.1.0",
"info": {
"title": "Kraken Spot REST Core",
"version": "1.0.0",
"description": "Curated Kraken Spot REST schema for market data, balances, orders, and open positions."
},
"servers": [
{
"url": "https://api.kraken.com"
}
],
"paths": {
"/0/public/Time": {
"get": {
"operationId": "getServerTime",
"summary": "Get server time",
"responses": {
"200": {
"description": "Server time response"
}
}
}
},
"/0/public/AssetPairs": {
"get": {
"operationId": "getAssetPairs",
"summary": "Get tradeable asset pairs",
"parameters": [
{
"name": "pair",
"in": "query",
"required": false,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Asset pairs response"
}
}
}
},
"/0/public/Ticker": {
"get": {
"operationId": "getTicker",
"summary": "Get ticker information",
"parameters": [
{
"name": "pair",
"in": "query",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Ticker response"
}
}
}
},
"/0/public/OHLC": {
"get": {
"operationId": "getOhlc",
"summary": "Get OHLC candles",
"parameters": [
{
"name": "pair",
"in": "query",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "interval",
"in": "query",
"required": false,
"schema": {
"type": "integer"
}
},
{
"name": "since",
"in": "query",
"required": false,
"schema": {
"type": "integer"
}
}
],
"responses": {
"200": {
"description": "OHLC response"
}
}
}
},
"/0/private/Balance": {
"post": {
"operationId": "getBalances",
"summary": "Get account balances",
"requestBody": {
"required": true,
"content": {
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/NonceOnlyRequest"
}
}
}
},
"responses": {
"200": {
"description": "Balance response"
}
}
}
},
"/0/private/OpenOrders": {
"post": {
"operationId": "getOpenOrders",
"summary": "Get open orders",
"requestBody": {
"required": true,
"content": {
"application/x-www-form-urlencoded": {
"schema": {
"allOf": [
{
"$ref": "#/components/schemas/NonceOnlyRequest"
},
{
"type": "object",
"properties": {
"trades": {
"type": "boolean"
},
"userref": {
"type": "integer"
}
}
}
]
}
}
}
},
"responses": {
"200": {
"description": "Open orders response"
}
}
}
},
"/0/private/OpenPositions": {
"post": {
"operationId": "getOpenPositions",
"summary": "Get open positions",
"requestBody": {
"required": true,
"content": {
"application/x-www-form-urlencoded": {
"schema": {
"allOf": [
{
"$ref": "#/components/schemas/NonceOnlyRequest"
},
{
"type": "object",
"properties": {
"txid": {
"type": "string"
},
"docalcs": {
"type": "boolean"
}
}
}
]
}
}
}
},
"responses": {
"200": {
"description": "Open positions response"
}
}
}
},
"/0/private/AddOrder": {
"post": {
"operationId": "addOrder",
"summary": "Place an order",
"requestBody": {
"required": true,
"content": {
"application/x-www-form-urlencoded": {
"schema": {
"allOf": [
{
"$ref": "#/components/schemas/NonceOnlyRequest"
},
{
"type": "object",
"required": [
"pair",
"type",
"ordertype",
"volume"
],
"properties": {
"pair": {
"type": "string"
},
"type": {
"type": "string",
"enum": [
"buy",
"sell"
]
},
"ordertype": {
"type": "string",
"enum": [
"market",
"limit"
]
},
"price": {
"type": "string"
},
"volume": {
"type": "string"
},
"validate": {
"type": "boolean"
}
}
}
]
}
}
}
},
"responses": {
"200": {
"description": "Add order response"
}
}
}
},
"/0/private/CancelOrder": {
"post": {
"operationId": "cancelOrder",
"summary": "Cancel an order",
"requestBody": {
"required": true,
"content": {
"application/x-www-form-urlencoded": {
"schema": {
"allOf": [
{
"$ref": "#/components/schemas/NonceOnlyRequest"
},
{
"type": "object",
"required": [
"txid"
],
"properties": {
"txid": {
"type": "string"
}
}
}
]
}
}
}
},
"responses": {
"200": {
"description": "Cancel order response"
}
}
}
}
},
"components": {
"schemas": {
"NonceOnlyRequest": {
"type": "object",
"required": [
"nonce"
],
"properties": {
"nonce": {
"type": "integer"
}
}
}
}
}
}
FILE:references/usage-patterns.md
# Kraken REST Skill - Usage Patterns
## Link Setup
```bash
command -v kraken-openapi-cli
uxc link kraken-openapi-cli https://api.kraken.com \
--schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/kraken-openapi-skill/references/kraken-public.openapi.json
kraken-openapi-cli -h
```
## Read Examples
```bash
# Read server time
kraken-openapi-cli get:/0/public/Time
# Read asset pair metadata
kraken-openapi-cli get:/0/public/AssetPairs pair=XBTUSD
# Read ticker
kraken-openapi-cli get:/0/public/Ticker pair=XBTUSD
# Read OHLC candles
kraken-openapi-cli get:/0/public/OHLC pair=XBTUSD interval=60
# Read order book snapshot
kraken-openapi-cli get:/0/public/Depth pair=XBTUSD count=20
```
## Guardrail Note
- Keep this v1 skill on public reads only because Kraken private REST auth uses provider-specific header signing and nonce handling not yet packaged into a reusable `uxc` signer flow.
## Fallback Equivalence
- `kraken-openapi-cli <operation> ...` is equivalent to
`uxc https://api.kraken.com --schema-url <kraken_public_openapi_schema> <operation> ...`.
FILE:scripts/validate.sh
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "BASH_SOURCE[0]")/../../.." && pwd)"
SKILL_DIR="ROOT_DIR/skills/kraken-openapi-skill"
SKILL_FILE="SKILL_DIR/SKILL.md"
OPENAI_FILE="SKILL_DIR/agents/openai.yaml"
USAGE_FILE="SKILL_DIR/references/usage-patterns.md"
SCHEMA_FILE="SKILL_DIR/references/kraken-public.openapi.json"
fail() {
printf '[validate] error: %s\n' "$*" >&2
exit 1
}
need_cmd() {
command -v "$1" >/dev/null 2>&1 || fail "required command not found: $1"
}
need_cmd jq
need_cmd rg
for file in "SKILL_FILE" "OPENAI_FILE" "USAGE_FILE" "SCHEMA_FILE"; do
[[ -f "file" ]] || fail "missing required file: file"
done
jq -e '.openapi and .paths and .components' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'invalid OpenAPI schema JSON or missing .openapi/.paths/.components'
jq -e '.paths["/0/public/Time"] and .paths["/0/public/Ticker"]' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'OpenAPI schema missing expected Kraken paths'
rg -q '^name:\s*kraken-openapi-skill\s*$' "SKILL_FILE" || fail 'invalid skill name'
rg -q 'command -v kraken-openapi-cli' "SKILL_FILE" || fail 'missing link-first command check'
rg -q 'uxc link kraken-openapi-cli https://api.kraken.com --schema-url ' "SKILL_FILE" || fail 'missing fixed link create command with schema-url'
rg -q 'provider-specific header signing' "SKILL_FILE" "USAGE_FILE" || fail 'missing private auth boundary note'
rg -q 'read-only' "SKILL_FILE" || fail 'missing read-only guardrail'
rg -q '^\s*display_name:\s*"Kraken REST"\s*$' "OPENAI_FILE" || fail 'missing display_name'
rg -q '^\s*default_prompt:\s*".*\$kraken-openapi-skill.*"\s*$' "OPENAI_FILE" || fail 'default_prompt must mention $kraken-openapi-skill'
echo "skills/kraken-openapi-skill validation passed"
Operate KuCoin public exchange market APIs through UXC with a curated OpenAPI schema, market-first discovery, and explicit private-auth boundary notes.
---
name: kucoin-openapi-skill
description: Operate KuCoin public exchange market APIs through UXC with a curated OpenAPI schema, market-first discovery, and explicit private-auth boundary notes.
---
# KuCoin Unified API Skill
Use this skill to run KuCoin public market-data operations through `uxc` + OpenAPI.
Reuse the `uxc` skill for shared execution, auth, and error-handling guidance.
## Prerequisites
- `uxc` is installed and available in `PATH`.
- Network access to `https://api.kucoin.com`.
- Access to the curated OpenAPI schema URL:
- `https://raw.githubusercontent.com/holon-run/uxc/main/skills/kucoin-openapi-skill/references/kucoin-public.openapi.json`
## Scope
This skill covers a curated KuCoin public market surface for:
- symbol discovery
- all tickers
- order book snapshots
- candlestick reads
This skill does **not** cover:
- private account or order endpoints in v1
- websocket, margin, or broader platform products
## Authentication
Public market endpoints in this skill do not require credentials.
KuCoin private REST auth uses provider-specific headers and signing rules including passphrase handling. Keep this v1 skill public-data-only until a reusable KuCoin signer flow exists in `uxc`.
## Core Workflow
1. Use the fixed link command by default:
- `command -v kucoin-openapi-cli`
- If missing, create it:
`uxc link kucoin-openapi-cli https://api.kucoin.com --schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/kucoin-openapi-skill/references/kucoin-public.openapi.json`
- `kucoin-openapi-cli -h`
2. Inspect operation help before execution:
- `kucoin-openapi-cli get:/api/v1/symbols -h`
- `kucoin-openapi-cli get:/api/v1/market/allTickers -h`
3. Prefer narrow symbol reads first:
- `kucoin-openapi-cli get:/api/v1/market/orderbook/level2_20 symbol=BTC-USDT`
- `kucoin-openapi-cli get:/api/v1/market/candles symbol=BTC-USDT type=1hour`
## Operations
- `get:/api/v1/symbols`
- `get:/api/v1/market/allTickers`
- `get:/api/v1/market/orderbook/level2_20`
- `get:/api/v1/market/candles`
## Guardrails
- Keep automation on the JSON output envelope; do not use `--text`.
- Parse stable fields first: `ok`, `kind`, `protocol`, `data`, `error`.
- Treat this v1 skill as read-only.
- KuCoin symbols use dash-separated names such as `BTC-USDT`.
- `kucoin-openapi-cli <operation> ...` is equivalent to `uxc https://api.kucoin.com --schema-url <kucoin_public_openapi_schema> <operation> ...`.
## References
- Usage patterns: `references/usage-patterns.md`
- Curated OpenAPI schema: `references/kucoin-public.openapi.json`
- Official KuCoin auth docs: https://www.kucoin.com/docs-new/authentication
FILE:agents/openai.yaml
interface:
display_name: "KuCoin Unified API"
short_description: "KuCoin public market data via curated REST endpoints"
default_prompt: "Use $kucoin-openapi-skill to discover and execute KuCoin public market-data operations through UXC with help-first schema inspection, symbol-aware reads, and explicit private-auth boundary notes."
FILE:references/kucoin-public.openapi.json
{
"openapi": "3.0.3",
"info": {
"title": "KuCoin Public API",
"version": "v1",
"description": "Curated KuCoin public market-data surface for UXC."
},
"servers": [
{ "url": "https://api.kucoin.com" }
],
"components": {
"schemas": {}
},
"paths": {
"/api/v1/symbols": {
"get": {
"operationId": "listSymbols",
"responses": { "200": { "description": "Symbols returned" } }
}
},
"/api/v1/market/allTickers": {
"get": {
"operationId": "listAllTickers",
"responses": { "200": { "description": "Tickers returned" } }
}
},
"/api/v1/market/orderbook/level2_20": {
"get": {
"operationId": "getOrderbook20",
"parameters": [
{ "name": "symbol", "in": "query", "required": true, "schema": { "type": "string" } }
],
"responses": { "200": { "description": "Orderbook returned" } }
}
},
"/api/v1/market/candles": {
"get": {
"operationId": "getCandles",
"parameters": [
{ "name": "symbol", "in": "query", "required": true, "schema": { "type": "string" } },
{ "name": "type", "in": "query", "required": true, "schema": { "type": "string" } },
{ "name": "startAt", "in": "query", "schema": { "type": "integer" } },
{ "name": "endAt", "in": "query", "schema": { "type": "integer" } }
],
"responses": { "200": { "description": "Candles returned" } }
}
}
}
}
FILE:references/usage-patterns.md
# KuCoin Unified API Skill - Usage Patterns
## Link Setup
```bash
command -v kucoin-openapi-cli
uxc link kucoin-openapi-cli https://api.kucoin.com \
--schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/kucoin-openapi-skill/references/kucoin-public.openapi.json
kucoin-openapi-cli -h
```
## Read Examples
```bash
# Read symbols
kucoin-openapi-cli get:/api/v1/symbols
# Read all tickers
kucoin-openapi-cli get:/api/v1/market/allTickers
# Read order book snapshot
kucoin-openapi-cli get:/api/v1/market/orderbook/level2_20 symbol=BTC-USDT
# Read candles
kucoin-openapi-cli get:/api/v1/market/candles symbol=BTC-USDT type=1hour
```
## Guardrail Note
- Keep this v1 skill on public reads only because KuCoin private REST auth uses provider-specific headers and signing rules not yet packaged into a reusable `uxc` signer flow.
## Fallback Equivalence
- `kucoin-openapi-cli <operation> ...` is equivalent to
`uxc https://api.kucoin.com --schema-url <kucoin_public_openapi_schema> <operation> ...`.
FILE:scripts/validate.sh
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "BASH_SOURCE[0]")/../../.." && pwd)"
SKILL_DIR="ROOT_DIR/skills/kucoin-openapi-skill"
SKILL_FILE="SKILL_DIR/SKILL.md"
OPENAI_FILE="SKILL_DIR/agents/openai.yaml"
USAGE_FILE="SKILL_DIR/references/usage-patterns.md"
SCHEMA_FILE="SKILL_DIR/references/kucoin-public.openapi.json"
fail() {
printf '[validate] error: %s\n' "$*" >&2
exit 1
}
need_cmd() {
command -v "$1" >/dev/null 2>&1 || fail "required command not found: $1"
}
need_cmd jq
need_cmd rg
for file in "SKILL_FILE" "OPENAI_FILE" "USAGE_FILE" "SCHEMA_FILE"; do
[[ -f "file" ]] || fail "missing required file: file"
done
jq -e '.openapi and .paths and .components' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'invalid OpenAPI schema JSON or missing .openapi/.paths/.components'
jq -e '.paths["/api/v1/symbols"] and .paths["/api/v1/market/allTickers"]' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'OpenAPI schema missing expected KuCoin paths'
rg -q '^name:\s*kucoin-openapi-skill\s*$' "SKILL_FILE" || fail 'invalid skill name'
rg -q '^description:\s*.+' "SKILL_FILE" || fail 'missing description'
rg -q 'command -v kucoin-openapi-cli' "SKILL_FILE" || fail 'missing link-first command check'
rg -q 'uxc link kucoin-openapi-cli https://api.kucoin.com --schema-url ' "SKILL_FILE" || fail 'missing fixed link create command with schema-url'
rg -q 'provider-specific headers and signing rules' "SKILL_FILE" "USAGE_FILE" || fail 'missing private auth boundary note'
rg -q 'read-only' "SKILL_FILE" || fail 'missing read-only guardrail'
if rg -q -- "--args\\s+'\\{" "SKILL_FILE" "USAGE_FILE"; then
fail 'found banned legacy JSON argument pattern'
fi
rg -q '^\s*display_name:\s*"KuCoin Unified API"\s*$' "OPENAI_FILE" || fail 'missing display_name'
rg -q '^\s*short_description:\s*".+"\s*$' "OPENAI_FILE" || fail 'missing short_description'
rg -q '^\s*default_prompt:\s*".*\$kucoin-openapi-skill.*"\s*$' "OPENAI_FILE" || fail 'default_prompt must mention $kucoin-openapi-skill'
echo "skills/kucoin-openapi-skill validation passed"
Operate MEXC Spot REST APIs through UXC with a curated OpenAPI schema, HMAC query signing, and separate public/signed workflow guardrails.
---
name: mexc-openapi-skill
description: Operate MEXC Spot REST APIs through UXC with a curated OpenAPI schema, HMAC query signing, and separate public/signed workflow guardrails.
---
# MEXC Spot API Skill
Use this skill to run MEXC Spot REST operations through `uxc` + OpenAPI.
Reuse the `uxc` skill for shared execution, auth, and error-handling guidance.
## Prerequisites
- `uxc` is installed and available in `PATH`.
- Network access to `https://api.mexc.com`.
- Access to the curated OpenAPI schema URL:
- `https://raw.githubusercontent.com/holon-run/uxc/main/skills/mexc-openapi-skill/references/mexc-spot.openapi.json`
## Scope
This skill covers a curated MEXC Spot REST surface for:
- public market reads
- signed account reads
- signed order create, cancel, and lookup flows
This skill does **not** cover:
- futures APIs
- broader platform product families
## Authentication
Public market endpoints do not require credentials.
Signed Spot endpoints require:
- `api_key` field for `X-MEXC-APIKEY`
- `secret_key` field for HMAC SHA256 query signing
Create one credential:
```bash
uxc auth credential set mexc-spot \
--auth-type api_key \
--field api_key=env:MEXC_API_KEY \
--field secret_key=env:MEXC_SECRET_KEY
```
Add one signer binding:
```bash
uxc auth binding add \
--id mexc-spot \
--host api.mexc.com \
--path-prefix /api/v3 \
--scheme https \
--credential mexc-spot \
--signer-json '{"kind":"hmac_query_v1","algorithm":"hmac_sha256","signing_field":"secret_key","key_field":"api_key","key_placement":"header","key_name":"X-MEXC-APIKEY","signature_param":"signature","signature_encoding":"hex","timestamp_param":"timestamp","timestamp_unit":"milliseconds","canonicalization":{"mode":"preserve_order"}}' \
--priority 100
```
Validate the active mapping when auth looks wrong:
```bash
uxc auth binding match https://api.mexc.com/api/v3/account
```
## Core Workflow
1. Use the fixed link command by default:
- `command -v mexc-openapi-cli`
- If missing, create it:
`uxc link mexc-openapi-cli https://api.mexc.com --schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/mexc-openapi-skill/references/mexc-spot.openapi.json`
- `mexc-openapi-cli -h`
2. Inspect operation help before execution:
- `mexc-openapi-cli get:/api/v3/ticker/price -h`
- `mexc-openapi-cli get:/api/v3/account -h`
- `mexc-openapi-cli post:/api/v3/order -h`
3. Prefer public reads first:
- `mexc-openapi-cli get:/api/v3/ticker/price symbol=BTCUSDT`
- `mexc-openapi-cli get:/api/v3/depth symbol=BTCUSDT limit=20`
4. Use signed reads before writes:
- `mexc-openapi-cli get:/api/v3/account recvWindow=5000`
- `mexc-openapi-cli get:/api/v3/openOrders symbol=BTCUSDT recvWindow=5000`
## Operation Groups
### Public Market
- `get:/api/v3/ping`
- `get:/api/v3/exchangeInfo`
- `get:/api/v3/ticker/price`
- `get:/api/v3/ticker/24hr`
- `get:/api/v3/depth`
### Signed Reads
- `get:/api/v3/account`
- `get:/api/v3/openOrders`
- `get:/api/v3/order`
### Signed Writes
- `post:/api/v3/order`
- `delete:/api/v3/order`
## Guardrails
- Keep automation on the JSON output envelope; do not use `--text`.
- Parse stable fields first: `ok`, `kind`, `protocol`, `data`, `error`.
- Treat signed write operations as high-risk and require explicit confirmation before execution.
- `timestamp` and `signature` are injected by the signer binding; users normally provide business parameters plus optional `recvWindow`.
- Query `exchangeInfo` before placing orders so symbol filters and lot sizes are known.
- `mexc-openapi-cli <operation> ...` is equivalent to `uxc https://api.mexc.com --schema-url <mexc_spot_openapi_schema> <operation> ...`.
## References
- Usage patterns: `references/usage-patterns.md`
- Curated OpenAPI schema: `references/mexc-spot.openapi.json`
- Official MEXC Spot v3 docs: https://mexcdevelop.github.io/apidocs/spot_v3_en/
FILE:agents/openai.yaml
interface:
display_name: "MEXC Spot"
short_description: "MEXC public market, account, and order endpoints via curated Spot REST mapping"
default_prompt: "Use $mexc-openapi-skill to discover and execute MEXC Spot REST operations through UXC with public-market reads, HMAC query signer bindings for signed account/order flows, and explicit write guardrails."
FILE:references/mexc-spot.openapi.json
{
"openapi": "3.0.3",
"info": {
"title": "MEXC Spot API",
"version": "v1",
"description": "Curated MEXC Spot REST surface for public market data and core signed account/order workflows."
},
"servers": [
{ "url": "https://api.mexc.com" }
],
"components": {
"schemas": {
"CreateOrderRequest": {
"type": "object",
"required": ["symbol", "side", "type"],
"properties": {
"symbol": { "type": "string" },
"side": { "type": "string", "enum": ["BUY", "SELL"] },
"type": { "type": "string" },
"quantity": { "type": "number" },
"quoteOrderQty": { "type": "number" },
"price": { "type": "number" },
"timeInForce": { "type": "string" },
"recvWindow": { "type": "integer" }
}
}
}
},
"paths": {
"/api/v3/ping": {
"get": {
"operationId": "ping",
"responses": { "200": { "description": "Ping returned" } }
}
},
"/api/v3/exchangeInfo": {
"get": {
"operationId": "getExchangeInfo",
"parameters": [
{ "name": "symbol", "in": "query", "schema": { "type": "string" } }
],
"responses": { "200": { "description": "Exchange info returned" } }
}
},
"/api/v3/ticker/price": {
"get": {
"operationId": "getTickerPrice",
"parameters": [
{ "name": "symbol", "in": "query", "schema": { "type": "string" } }
],
"responses": { "200": { "description": "Price ticker returned" } }
}
},
"/api/v3/ticker/24hr": {
"get": {
"operationId": "getTicker24h",
"parameters": [
{ "name": "symbol", "in": "query", "schema": { "type": "string" } }
],
"responses": { "200": { "description": "24h ticker returned" } }
}
},
"/api/v3/depth": {
"get": {
"operationId": "getDepth",
"parameters": [
{ "name": "symbol", "in": "query", "required": true, "schema": { "type": "string" } },
{ "name": "limit", "in": "query", "schema": { "type": "integer" } }
],
"responses": { "200": { "description": "Depth returned" } }
}
},
"/api/v3/account": {
"get": {
"operationId": "getAccount",
"parameters": [
{ "name": "recvWindow", "in": "query", "schema": { "type": "integer" } }
],
"responses": { "200": { "description": "Account returned" } }
}
},
"/api/v3/openOrders": {
"get": {
"operationId": "getOpenOrders",
"parameters": [
{ "name": "symbol", "in": "query", "schema": { "type": "string" } },
{ "name": "recvWindow", "in": "query", "schema": { "type": "integer" } }
],
"responses": { "200": { "description": "Open orders returned" } }
}
},
"/api/v3/order": {
"get": {
"operationId": "getOrder",
"parameters": [
{ "name": "symbol", "in": "query", "required": true, "schema": { "type": "string" } },
{ "name": "orderId", "in": "query", "schema": { "type": "integer" } },
{ "name": "origClientOrderId", "in": "query", "schema": { "type": "string" } },
{ "name": "recvWindow", "in": "query", "schema": { "type": "integer" } }
],
"responses": { "200": { "description": "Order returned" } }
},
"post": {
"operationId": "createOrder",
"parameters": [
{ "name": "symbol", "in": "query", "required": true, "schema": { "type": "string" } },
{ "name": "side", "in": "query", "required": true, "schema": { "type": "string" } },
{ "name": "type", "in": "query", "required": true, "schema": { "type": "string" } },
{ "name": "quantity", "in": "query", "schema": { "type": "number" } },
{ "name": "quoteOrderQty", "in": "query", "schema": { "type": "number" } },
{ "name": "price", "in": "query", "schema": { "type": "number" } },
{ "name": "timeInForce", "in": "query", "schema": { "type": "string" } },
{ "name": "recvWindow", "in": "query", "schema": { "type": "integer" } }
],
"responses": { "200": { "description": "Order created" } }
},
"delete": {
"operationId": "cancelOrder",
"parameters": [
{ "name": "symbol", "in": "query", "required": true, "schema": { "type": "string" } },
{ "name": "orderId", "in": "query", "schema": { "type": "integer" } },
{ "name": "origClientOrderId", "in": "query", "schema": { "type": "string" } },
{ "name": "recvWindow", "in": "query", "schema": { "type": "integer" } }
],
"responses": { "200": { "description": "Order canceled" } }
}
}
}
}
FILE:references/usage-patterns.md
# MEXC Spot API Skill - Usage Patterns
## Link Setup
```bash
command -v mexc-openapi-cli
uxc link mexc-openapi-cli https://api.mexc.com \
--schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/mexc-openapi-skill/references/mexc-spot.openapi.json
mexc-openapi-cli -h
```
## Auth Setup
```bash
uxc auth credential set mexc-spot \
--auth-type api_key \
--field api_key=env:MEXC_API_KEY \
--field secret_key=env:MEXC_SECRET_KEY
SIGNER='{"kind":"hmac_query_v1","algorithm":"hmac_sha256","signing_field":"secret_key","key_field":"api_key","key_placement":"header","key_name":"X-MEXC-APIKEY","signature_param":"signature","signature_encoding":"hex","timestamp_param":"timestamp","timestamp_unit":"milliseconds","canonicalization":{"mode":"preserve_order"}}'
uxc auth binding add \
--id mexc-spot \
--host api.mexc.com \
--path-prefix /api/v3 \
--scheme https \
--credential mexc-spot \
--signer-json "$SIGNER" \
--priority 100
```
Validate the binding:
```bash
uxc auth binding match https://api.mexc.com/api/v3/account
```
## Read Examples
```bash
# Read ticker
mexc-openapi-cli get:/api/v3/ticker/price symbol=BTCUSDT
# Read depth
mexc-openapi-cli get:/api/v3/depth symbol=BTCUSDT limit=20
# Read account
mexc-openapi-cli get:/api/v3/account recvWindow=5000
# Read open orders
mexc-openapi-cli get:/api/v3/openOrders symbol=BTCUSDT recvWindow=5000
# Read one order
mexc-openapi-cli get:/api/v3/order symbol=BTCUSDT orderId=123456 recvWindow=5000
```
## Write Examples
```bash
# Place an order
mexc-openapi-cli post:/api/v3/order \
symbol=BTCUSDT \
side=BUY \
type=LIMIT \
quantity=0.001 \
price=25000 \
timeInForce=GTC \
recvWindow=5000
# Cancel an order
mexc-openapi-cli delete:/api/v3/order symbol=BTCUSDT orderId=123456 recvWindow=5000
```
## Fallback Equivalence
- `mexc-openapi-cli <operation> ...` is equivalent to
`uxc https://api.mexc.com --schema-url <mexc_spot_openapi_schema> <operation> ...`.
FILE:scripts/validate.sh
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "BASH_SOURCE[0]")/../../.." && pwd)"
SKILL_DIR="ROOT_DIR/skills/mexc-openapi-skill"
SKILL_FILE="SKILL_DIR/SKILL.md"
OPENAI_FILE="SKILL_DIR/agents/openai.yaml"
USAGE_FILE="SKILL_DIR/references/usage-patterns.md"
SCHEMA_FILE="SKILL_DIR/references/mexc-spot.openapi.json"
fail() {
printf '[validate] error: %s\n' "$*" >&2
exit 1
}
need_cmd() {
command -v "$1" >/dev/null 2>&1 || fail "required command not found: $1"
}
need_cmd jq
need_cmd rg
for file in "SKILL_FILE" "OPENAI_FILE" "USAGE_FILE" "SCHEMA_FILE"; do
[[ -f "file" ]] || fail "missing required file: file"
done
jq -e '.openapi and .paths and .components' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'invalid OpenAPI schema JSON or missing .openapi/.paths/.components'
jq -e '.paths["/api/v3/ticker/price"] and .paths["/api/v3/account"] and .paths["/api/v3/order"]' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'OpenAPI schema missing expected MEXC paths'
rg -q '^name:\s*mexc-openapi-skill\s*$' "SKILL_FILE" || fail 'invalid skill name'
rg -q 'command -v mexc-openapi-cli' "SKILL_FILE" || fail 'missing link-first command check'
rg -q 'uxc link mexc-openapi-cli https://api.mexc.com --schema-url ' "SKILL_FILE" || fail 'missing fixed link create command with schema-url'
rg -q -- '--signer-json' "SKILL_FILE" "USAGE_FILE" || fail 'missing signer-json guidance'
rg -q 'X-MEXC-APIKEY' "SKILL_FILE" "USAGE_FILE" || fail 'missing API key header guidance'
rg -q 'high-risk' "SKILL_FILE" || fail 'missing write guardrail'
rg -q 'uxc auth binding match https://api.mexc.com/api/v3/account' "SKILL_FILE" || fail 'missing binding match example'
rg -q '^\s*display_name:\s*"MEXC Spot"\s*$' "OPENAI_FILE" || fail 'missing display_name'
rg -q '^\s*default_prompt:\s*".*\$mexc-openapi-skill.*"\s*$' "OPENAI_FILE" || fail 'default_prompt must mention $mexc-openapi-skill'
echo "skills/mexc-openapi-skill validation passed"
Operate Coinbase Advanced Trade REST APIs through UXC with a curated OpenAPI schema, products-first discovery, and explicit JWT bearer auth guidance.
---
name: coinbase-openapi-skill
description: Operate Coinbase Advanced Trade REST APIs through UXC with a curated OpenAPI schema, products-first discovery, and explicit JWT bearer auth guidance.
---
# Coinbase Advanced Trade Skill
Use this skill to run Coinbase Advanced Trade REST operations through `uxc` + OpenAPI.
Reuse the `uxc` skill for shared execution, auth, and error-handling guidance.
## Prerequisites
- `uxc` is installed and available in `PATH`.
- Network access to `https://api.coinbase.com`.
- Access to the curated OpenAPI schema URL:
- `https://raw.githubusercontent.com/holon-run/uxc/main/skills/coinbase-openapi-skill/references/coinbase-advanced-trade.openapi.json`
## Scope
This skill covers a curated Coinbase Advanced Trade surface for:
- product and best-bid-ask market reads
- account summary reads
- order create, cancel, and lookup workflows
This skill does **not** cover:
- Coinbase Exchange APIs
- Coinbase Prime APIs
- Coinbase Derivatives APIs
- wallet or retail app product families outside Advanced Trade
## Authentication
Public product endpoints can be read without credentials.
Private account and order endpoints require a Coinbase Advanced Trade bearer JWT. `uxc` now supports Coinbase's request-scoped JWT flow directly through `jwt_bearer_v1`, so you can store the API key id and private key in a credential and let `uxc` mint the short-lived bearer token per request.
Recommended v1 setup:
1. Download or copy the Coinbase API key material:
- `key_id`: `organizations/{org_id}/apiKeys/{key_id}`
- `private_key`: Coinbase exports either `-----BEGIN EC PRIVATE KEY-----` or `-----BEGIN PRIVATE KEY-----`; `uxc` accepts both PEM forms for ES256.
2. Store those values in a local credential.
3. Bind the credential to `api.coinbase.com` with a `jwt_bearer_v1` signer.
```bash
uxc auth credential set coinbase-advanced-trade \
--auth-type api_key \
--field key_id=env:COINBASE_KEY_ID \
--field private_key=env:COINBASE_PRIVATE_KEY
uxc auth binding add \
--id coinbase-advanced-trade \
--host api.coinbase.com \
--path-prefix /api/v3/brokerage \
--scheme https \
--credential coinbase-advanced-trade \
--signer-json '{"kind":"jwt_bearer_v1","algorithm":"es256","private_key_field":"private_key","header_typ":"JWT","header_kid_field":"key_id","expires_in_seconds":120,"claims":{"static":{"iss":"cdp"},"from_fields":{"sub":"key_id"},"time":{"nbf":"now","exp":"now_plus_ttl"}},"request_claim":{"name":"uri","format":"string","value_template":"{{request.method}} {{request.host}}{{request.path}}"}}' \
--priority 100
```
Validate the active mapping when auth looks wrong:
```bash
uxc auth binding match https://api.coinbase.com/api/v3/brokerage/accounts
```
## Core Workflow
1. Use the fixed link command by default:
- `command -v coinbase-openapi-cli`
- If missing, create it:
`uxc link coinbase-openapi-cli https://api.coinbase.com --schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/coinbase-openapi-skill/references/coinbase-advanced-trade.openapi.json`
- `coinbase-openapi-cli -h`
2. Inspect operation help before execution:
- `coinbase-openapi-cli get:/api/v3/brokerage/products -h`
- `coinbase-openapi-cli get:/api/v3/brokerage/accounts -h`
- `coinbase-openapi-cli post:/api/v3/brokerage/orders -h`
3. Prefer product reads before private account or order workflows:
- `coinbase-openapi-cli get:/api/v3/brokerage/products product_type=SPOT limit=20`
- `coinbase-openapi-cli get:/api/v3/brokerage/best_bid_ask product_ids=BTC-USD,ETH-USD`
4. Treat all order placement and cancellation as high-risk writes.
## Operations
- `get:/api/v3/brokerage/products`
- `get:/api/v3/brokerage/products/{product_id}`
- `get:/api/v3/brokerage/best_bid_ask`
- `get:/api/v3/brokerage/accounts`
- `get:/api/v3/brokerage/accounts/{account_uuid}`
- `post:/api/v3/brokerage/orders`
- `post:/api/v3/brokerage/orders/batch_cancel`
- `get:/api/v3/brokerage/orders/historical/{order_id}`
- `get:/api/v3/brokerage/orders/historical/batch`
## Guardrails
- Keep automation on the JSON output envelope; do not use `--text`.
- Parse stable fields first: `ok`, `kind`, `protocol`, `data`, `error`.
- `uxc` mints a fresh short-lived Coinbase JWT on each private request; do not try to bind a stale pre-generated bearer token when `jwt_bearer_v1` is available.
- Coinbase exports ES256 private keys in more than one PEM form; this skill expects the raw downloaded PEM and does not require a manual PKCS#8 conversion step.
- Treat `post:/api/v3/brokerage/orders` and `post:/api/v3/brokerage/orders/batch_cancel` as high-risk writes.
- Keep initial product/account pulls narrow with small `limit` values.
- `coinbase-openapi-cli <operation> ...` is equivalent to `uxc https://api.coinbase.com --schema-url <coinbase_advanced_trade_openapi_schema> <operation> ...`.
## References
- Usage patterns: `references/usage-patterns.md`
- Curated OpenAPI schema: `references/coinbase-advanced-trade.openapi.json`
- Coinbase Advanced Trade overview: https://docs.cdp.coinbase.com/coinbase-app/advanced-trade-apis/overview
FILE:agents/openai.yaml
interface:
display_name: "Coinbase Advanced Trade"
short_description: "Products, accounts, and orders via Coinbase Advanced Trade through UXC"
default_prompt: "Use $coinbase-openapi-skill to discover and execute Coinbase Advanced Trade REST operations through UXC with products-first discovery, built-in jwt_bearer_v1 auth, and explicit write guardrails."
FILE:references/coinbase-advanced-trade.openapi.json
{
"openapi": "3.0.3",
"info": {
"title": "Coinbase Advanced Trade API",
"version": "v1",
"description": "Curated Coinbase Advanced Trade REST surface for product discovery, account summaries, and core order workflows."
},
"servers": [
{
"url": "https://api.coinbase.com"
}
],
"components": {
"securitySchemes": {
"bearerAuth": {
"type": "http",
"scheme": "bearer"
}
},
"schemas": {
"OrderConfiguration": {
"type": "object",
"additionalProperties": true
},
"CreateOrderRequest": {
"type": "object",
"required": [
"client_order_id",
"product_id",
"side",
"order_configuration"
],
"properties": {
"client_order_id": { "type": "string" },
"product_id": { "type": "string" },
"side": { "type": "string", "enum": ["BUY", "SELL"] },
"order_configuration": { "$ref": "#/components/schemas/OrderConfiguration" }
}
},
"BatchCancelRequest": {
"type": "object",
"required": ["order_ids"],
"properties": {
"order_ids": {
"type": "array",
"items": { "type": "string" }
}
}
}
}
},
"paths": {
"/api/v3/brokerage/products": {
"get": {
"operationId": "listProducts",
"parameters": [
{ "name": "limit", "in": "query", "schema": { "type": "integer" } },
{ "name": "offset", "in": "query", "schema": { "type": "integer" } },
{ "name": "product_type", "in": "query", "schema": { "type": "string" } },
{ "name": "product_ids", "in": "query", "schema": { "type": "string" } }
],
"responses": {
"200": { "description": "Products listed" }
}
}
},
"/api/v3/brokerage/products/{product_id}": {
"get": {
"operationId": "getProduct",
"parameters": [
{ "name": "product_id", "in": "path", "required": true, "schema": { "type": "string" } }
],
"responses": {
"200": { "description": "Product returned" }
}
}
},
"/api/v3/brokerage/best_bid_ask": {
"get": {
"operationId": "getBestBidAsk",
"parameters": [
{ "name": "product_ids", "in": "query", "schema": { "type": "string" } }
],
"responses": {
"200": { "description": "Best bid ask returned" }
}
}
},
"/api/v3/brokerage/accounts": {
"get": {
"operationId": "listAccounts",
"security": [{ "bearerAuth": [] }],
"parameters": [
{ "name": "limit", "in": "query", "schema": { "type": "integer" } },
{ "name": "cursor", "in": "query", "schema": { "type": "string" } }
],
"responses": {
"200": { "description": "Accounts listed" }
}
}
},
"/api/v3/brokerage/accounts/{account_uuid}": {
"get": {
"operationId": "getAccount",
"security": [{ "bearerAuth": [] }],
"parameters": [
{ "name": "account_uuid", "in": "path", "required": true, "schema": { "type": "string" } }
],
"responses": {
"200": { "description": "Account returned" }
}
}
},
"/api/v3/brokerage/orders": {
"post": {
"operationId": "createOrder",
"security": [{ "bearerAuth": [] }],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/CreateOrderRequest" }
}
}
},
"responses": {
"200": { "description": "Order created" }
}
}
},
"/api/v3/brokerage/orders/batch_cancel": {
"post": {
"operationId": "cancelOrders",
"security": [{ "bearerAuth": [] }],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/BatchCancelRequest" }
}
}
},
"responses": {
"200": { "description": "Cancel submitted" }
}
}
},
"/api/v3/brokerage/orders/historical/{order_id}": {
"get": {
"operationId": "getOrder",
"security": [{ "bearerAuth": [] }],
"parameters": [
{ "name": "order_id", "in": "path", "required": true, "schema": { "type": "string" } }
],
"responses": {
"200": { "description": "Order returned" }
}
}
},
"/api/v3/brokerage/orders/historical/batch": {
"get": {
"operationId": "listOrders",
"security": [{ "bearerAuth": [] }],
"parameters": [
{ "name": "product_id", "in": "query", "schema": { "type": "string" } },
{ "name": "order_status", "in": "query", "schema": { "type": "string" } },
{ "name": "limit", "in": "query", "schema": { "type": "integer" } },
{ "name": "cursor", "in": "query", "schema": { "type": "string" } }
],
"responses": {
"200": { "description": "Orders listed" }
}
}
}
}
}
FILE:references/usage-patterns.md
# Coinbase Advanced Trade Skill - Usage Patterns
## Link Setup
```bash
command -v coinbase-openapi-cli
uxc link coinbase-openapi-cli https://api.coinbase.com \
--schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/coinbase-openapi-skill/references/coinbase-advanced-trade.openapi.json
coinbase-openapi-cli -h
```
## Auth Setup
Store the Coinbase API key id and private key, then let `uxc` mint the short-lived Advanced Trade JWT per request:
```bash
uxc auth credential set coinbase-advanced-trade \
--auth-type api_key \
--field key_id=env:COINBASE_KEY_ID \
--field private_key=env:COINBASE_PRIVATE_KEY
uxc auth binding add \
--id coinbase-advanced-trade \
--host api.coinbase.com \
--path-prefix /api/v3/brokerage \
--scheme https \
--credential coinbase-advanced-trade \
--signer-json '{"kind":"jwt_bearer_v1","algorithm":"es256","private_key_field":"private_key","header_typ":"JWT","header_kid_field":"key_id","expires_in_seconds":120,"claims":{"static":{"iss":"cdp"},"from_fields":{"sub":"key_id"},"time":{"nbf":"now","exp":"now_plus_ttl"}},"request_claim":{"name":"uri","format":"string","value_template":"{{request.method}} {{request.host}}{{request.path}}"}}' \
--priority 100
```
`COINBASE_PRIVATE_KEY` may be either `-----BEGIN EC PRIVATE KEY-----` or `-----BEGIN PRIVATE KEY-----`.
Validate the binding:
```bash
uxc auth binding match https://api.coinbase.com/api/v3/brokerage/accounts
```
## Read Examples
```bash
# List spot products
coinbase-openapi-cli get:/api/v3/brokerage/products product_type=SPOT limit=20
# Read one product
coinbase-openapi-cli get:/api/v3/brokerage/products/{product_id} product_id=BTC-USD
# Read best bid/ask for a narrow product set
coinbase-openapi-cli get:/api/v3/brokerage/best_bid_ask product_ids=BTC-USD,ETH-USD
# List accounts
coinbase-openapi-cli get:/api/v3/brokerage/accounts limit=20
# Read one account
coinbase-openapi-cli get:/api/v3/brokerage/accounts/{account_uuid} account_uuid=<account_uuid>
# List historical orders
coinbase-openapi-cli get:/api/v3/brokerage/orders/historical/batch product_id=BTC-USD order_status=OPEN limit=20
# Read one order
coinbase-openapi-cli get:/api/v3/brokerage/orders/historical/{order_id} order_id=<order_id>
```
## Write Examples
```bash
# Create a live limit order
coinbase-openapi-cli post:/api/v3/brokerage/orders \
'{"client_order_id":"uxc-demo-order-1","product_id":"BTC-USD","side":"BUY","order_configuration":{"limit_limit_gtc":{"base_size":"0.001","limit_price":"25000.00","post_only":true}}}'
# Cancel orders in batch
coinbase-openapi-cli post:/api/v3/brokerage/orders/batch_cancel \
'{"order_ids":["<order_id_1>","<order_id_2>"]}'
```
## Fallback Equivalence
- `coinbase-openapi-cli <operation> ...` is equivalent to
`uxc https://api.coinbase.com --schema-url <coinbase_advanced_trade_openapi_schema> <operation> ...`.
FILE:scripts/validate.sh
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "BASH_SOURCE[0]")/../../.." && pwd)"
SKILL_DIR="ROOT_DIR/skills/coinbase-openapi-skill"
SKILL_FILE="SKILL_DIR/SKILL.md"
OPENAI_FILE="SKILL_DIR/agents/openai.yaml"
USAGE_FILE="SKILL_DIR/references/usage-patterns.md"
SCHEMA_FILE="SKILL_DIR/references/coinbase-advanced-trade.openapi.json"
fail() {
printf '[validate] error: %s\n' "$*" >&2
exit 1
}
need_cmd() {
command -v "$1" >/dev/null 2>&1 || fail "required command not found: $1"
}
need_cmd jq
need_cmd rg
for file in "SKILL_FILE" "OPENAI_FILE" "USAGE_FILE" "SCHEMA_FILE"; do
[[ -f "file" ]] || fail "missing required file: file"
done
jq -e '.openapi and .paths and .components' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'invalid OpenAPI schema JSON or missing .openapi/.paths/.components'
jq -e '.paths["/api/v3/brokerage/products"] and .paths["/api/v3/brokerage/orders"]' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'OpenAPI schema missing expected Coinbase paths'
rg -q '^name:\s*coinbase-openapi-skill\s*$' "SKILL_FILE" || fail 'invalid skill name'
rg -q '^description:\s*.+' "SKILL_FILE" || fail 'missing description'
rg -q 'command -v coinbase-openapi-cli' "SKILL_FILE" || fail 'missing link-first command check'
rg -q 'uxc link coinbase-openapi-cli https://api.coinbase.com --schema-url ' "SKILL_FILE" || fail 'missing fixed link create command with schema-url'
rg -q 'coinbase-openapi-cli get:/api/v3/brokerage/products -h' "SKILL_FILE" || fail 'missing operation-level help example'
rg -q 'jwt_bearer_v1' "SKILL_FILE" "USAGE_FILE" || fail 'missing jwt_bearer_v1 signer guidance'
rg -q 'COINBASE_KEY_ID' "SKILL_FILE" "USAGE_FILE" || fail 'missing key id guidance'
rg -q 'COINBASE_PRIVATE_KEY' "SKILL_FILE" "USAGE_FILE" || fail 'missing private key guidance'
rg -q 'uxc auth binding match https://api.coinbase.com/api/v3/brokerage/accounts' "SKILL_FILE" || fail 'missing binding match check'
rg -q 'high-risk writes' "SKILL_FILE" || fail 'missing high-risk write guidance'
if rg -q -- "--args\\s+'\\{" "SKILL_FILE" "USAGE_FILE"; then
fail 'found banned legacy JSON argument pattern'
fi
rg -q '^\s*display_name:\s*"Coinbase Advanced Trade"\s*$' "OPENAI_FILE" || fail 'missing display_name'
rg -q '^\s*short_description:\s*".+"\s*$' "OPENAI_FILE" || fail 'missing short_description'
rg -q '^\s*default_prompt:\s*".*\$coinbase-openapi-skill.*"\s*$' "OPENAI_FILE" || fail 'default_prompt must mention $coinbase-openapi-skill'
echo "skills/coinbase-openapi-skill validation passed"
Operate DingTalk messaging APIs through UXC with a curated OpenAPI schema, app-token bearer auth, and robot/service-group guardrails.
---
name: dingtalk-openapi-skill
description: Operate DingTalk messaging APIs through UXC with a curated OpenAPI schema, app-token bearer auth, and robot/service-group guardrails.
---
# DingTalk Messaging Skill
Use this skill to run DingTalk messaging operations through `uxc` + OpenAPI.
Reuse the `uxc` skill for shared execution, auth, and error-handling guidance.
## Prerequisites
- `uxc` is installed and available in `PATH`.
- Network access to `https://api.dingtalk.com/v1.0`.
- Access to the curated OpenAPI schema URL:
- `https://raw.githubusercontent.com/holon-run/uxc/main/skills/dingtalk-openapi-skill/references/dingtalk-messaging.openapi.json`
- A DingTalk internal app or app suite with bot messaging permissions enabled.
- A DingTalk app `appKey` + `appSecret`, or a current `accessToken` if you are using the manual fallback path.
- Robot code, conversation identifiers, and user identifiers for the target send flows.
## Scope
This skill covers a narrow IM-focused request/response surface:
- one-to-one bot sends
- group bot sends
- service group sends
- minimal user lookup by `unionId`
This skill does **not** cover:
- approval, attendance, admin, or broader enterprise app workflows
- old `oapi.dingtalk.com` endpoints
- custom robot webhook token/signature flows
- inbound callback or webhook receiver runtime
## Subscribe / Stream Mode Status
DingTalk has event-delivery flows such as Stream Mode, but those flows are outside the current scope of this skill.
Current `uxc subscribe` status:
- this skill is validated only for request/response messaging operations
- DingTalk inbound event/message intake is **not** currently validated through `uxc subscribe`
Treat DingTalk as a possible future subscribe target via Stream Mode rather than a currently supported IM subscribe provider.
## API Surface Choice
This skill is intentionally pinned to the newer DingTalk Open Platform host:
- `https://api.dingtalk.com/v1.0`
The older `oapi.dingtalk.com` surface is intentionally excluded from v1 to keep auth and schema shape consistent.
## Authentication
DingTalk v1 APIs use app `accessToken` credentials.
Preferred setup is to store `appKey` + `appSecret` as credential fields and let `uxc auth bootstrap` fetch and refresh the short-lived access token automatically.
Bootstrap-managed setup:
```bash
uxc auth credential set dingtalk-app \
--auth-type bearer \
--field app_key=env:DINGTALK_APP_KEY \
--field app_secret=env:DINGTALK_APP_SECRET
uxc auth bootstrap set dingtalk-app \
--token-endpoint https://api.dingtalk.com/v1.0/oauth2/accessToken \
--header 'Content-Type=application/json' \
--request-json '{"appKey":"{{field:app_key}}","appSecret":"{{field:app_secret}}"}' \
--access-token-pointer /accessToken \
--expires-in-pointer /expireIn
uxc auth binding add \
--id dingtalk-app \
--host api.dingtalk.com \
--path-prefix /v1.0 \
--scheme https \
--credential dingtalk-app \
--priority 100
```
Manual fallback if you already have an app access token:
```bash
curl -sS https://api.dingtalk.com/v1.0/oauth2/accessToken \
-H 'Content-Type: application/json' \
-d '{"appKey":"dingxxxx","appSecret":"xxxx"}'
```
Configure one bearer credential and bind it to the DingTalk API host:
```bash
uxc auth credential set dingtalk-app \
--auth-type bearer \
--secret-env DINGTALK_ACCESS_TOKEN
uxc auth binding add \
--id dingtalk-app \
--host api.dingtalk.com \
--path-prefix /v1.0 \
--scheme https \
--credential dingtalk-app \
--priority 100
```
Validate the active mapping when auth looks wrong:
```bash
uxc auth binding match https://api.dingtalk.com/v1.0
```
## Core Workflow
1. Use the fixed link command by default:
- `command -v dingtalk-openapi-cli`
- If missing, create it:
`uxc link dingtalk-openapi-cli https://api.dingtalk.com/v1.0 --schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/dingtalk-openapi-skill/references/dingtalk-messaging.openapi.json`
- `dingtalk-openapi-cli -h`
2. Inspect operation schema first:
- `dingtalk-openapi-cli get:/contact/users/{unionId} -h`
- `dingtalk-openapi-cli post:/robot/oToMessages/batchSend -h`
- `dingtalk-openapi-cli post:/robot/groupMessages/send -h`
3. Prefer read/setup validation before writes:
- `dingtalk-openapi-cli get:/contact/users/{unionId} unionId=$DINGTALK_UNION_ID`
- `dingtalk-openapi-cli post:/robot/oToMessages/batchSend -h`
- `dingtalk-openapi-cli post:/serviceGroup/messages/send -h`
4. Execute with key/value or positional JSON:
- key/value:
`dingtalk-openapi-cli get:/contact/users/{unionId} unionId=$DINGTALK_UNION_ID language=zh_CN`
- positional JSON:
`dingtalk-openapi-cli post:/robot/groupMessages/send '{"openConversationId":"cidxxxx","robotCode":"dingxxxx","msgKey":"sampleText","msgParam":"{\"content\":\"Hello from UXC\"}"}'`
## Operation Groups
### User Lookup
- `get:/contact/users/{unionId}`
### Messaging
- `post:/robot/oToMessages/batchSend`
- `post:/robot/groupMessages/send`
- `post:/serviceGroup/messages/send`
## Guardrails
- Keep automation on the JSON output envelope; do not use `--text`.
- Parse stable fields first: `ok`, `kind`, `protocol`, `data`, `error`.
- Prefer `uxc auth bootstrap` over manual token management. Manual `accessToken` setup is still supported as a fallback.
- All three send operations are high-risk writes. Require explicit user confirmation before execution.
- DingTalk `msgParam` is a JSON-encoded string payload, not a nested JSON object. Build and validate that string carefully before sending.
- `robotCode`, `openConversationId`, `coolAppCode`, and target identifiers are all provider-specific routing fields. Missing any of them generally means the send will fail even if auth is valid.
- This v1 wrapper does not include custom robot webhook token/sign flows; use app-based APIs only.
- `dingtalk-openapi-cli <operation> ...` is equivalent to `uxc https://api.dingtalk.com/v1.0 --schema-url <dingtalk_openapi_schema> <operation> ...`.
## References
- Usage patterns: `references/usage-patterns.md`
- Curated OpenAPI schema: `references/dingtalk-messaging.openapi.json`
- DingTalk developer docs: https://open.dingtalk.com/document/
FILE:agents/openai.yaml
interface:
display_name: "DingTalk Messaging"
short_description: "Operate DingTalk v1.0 messaging APIs via UXC + curated OpenAPI schema"
default_prompt: "Use $dingtalk-openapi-skill to discover and execute DingTalk messaging operations through UXC with app-token bearer auth, robot/service-group send scope, and msgParam string guardrails."
FILE:references/dingtalk-messaging.openapi.json
{
"openapi": "3.0.3",
"info": {
"title": "DingTalk Messaging API (Curated)",
"version": "1.0.0",
"description": "Curated DingTalk v1.0 messaging and contact surface for UXC enterprise chat workflows."
},
"servers": [
{
"url": "https://api.dingtalk.com/v1.0"
}
],
"security": [
{
"DingTalkBearerAuth": []
}
],
"paths": {
"/contact/users/{unionId}": {
"get": {
"summary": "Get one DingTalk user by unionId",
"parameters": [
{
"name": "unionId",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "DingTalk user unionId"
},
{
"name": "language",
"in": "query",
"required": false,
"schema": {
"type": "string",
"enum": [
"zh_CN",
"en_US"
]
},
"description": "Optional response language hint"
}
],
"responses": {
"200": {
"description": "User detail response"
}
}
}
},
"/robot/oToMessages/batchSend": {
"post": {
"summary": "Send one-to-one robot messages to multiple users",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/OToBatchSendRequest"
}
}
}
},
"responses": {
"200": {
"description": "One-to-one batch send response"
}
}
}
},
"/robot/groupMessages/send": {
"post": {
"summary": "Send a robot message to a group conversation",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/GroupMessageSendRequest"
}
}
}
},
"responses": {
"200": {
"description": "Group message send response"
}
}
}
},
"/serviceGroup/messages/send": {
"post": {
"summary": "Send a message into a service group conversation",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ServiceGroupMessageSendRequest"
}
}
}
},
"responses": {
"200": {
"description": "Service group message send response"
}
}
}
}
},
"components": {
"securitySchemes": {
"DingTalkBearerAuth": {
"type": "http",
"scheme": "bearer",
"bearerFormat": "accessToken"
}
},
"schemas": {
"OToBatchSendRequest": {
"type": "object",
"required": [
"robotCode",
"userIds",
"msgKey",
"msgParam"
],
"properties": {
"robotCode": {
"type": "string",
"description": "Robot code for the DingTalk app or bot"
},
"userIds": {
"type": "array",
"minItems": 1,
"items": {
"type": "string"
},
"description": "Target user IDs that should receive the one-to-one message"
},
"msgKey": {
"type": "string",
"description": "Message template key such as sampleText, sampleMarkdown, or another supported DingTalk robot message key"
},
"msgParam": {
"type": "string",
"description": "JSON-encoded message payload string expected by DingTalk for the selected msgKey"
}
},
"additionalProperties": false
},
"GroupMessageSendRequest": {
"type": "object",
"required": [
"robotCode",
"openConversationId",
"msgKey",
"msgParam"
],
"properties": {
"robotCode": {
"type": "string",
"description": "Robot code for the DingTalk app or bot"
},
"openConversationId": {
"type": "string",
"description": "Open conversation ID for the target group"
},
"msgKey": {
"type": "string",
"description": "Message template key such as sampleText, sampleMarkdown, or another supported DingTalk robot message key"
},
"msgParam": {
"type": "string",
"description": "JSON-encoded message payload string expected by DingTalk for the selected msgKey"
}
},
"additionalProperties": false
},
"ServiceGroupMessageSendRequest": {
"type": "object",
"required": [
"coolAppCode",
"robotCode",
"openConversationId",
"msgKey",
"msgParam"
],
"properties": {
"coolAppCode": {
"type": "string",
"description": "Cool app code associated with the service group capability"
},
"robotCode": {
"type": "string",
"description": "Robot code for the DingTalk app or bot"
},
"openConversationId": {
"type": "string",
"description": "Open conversation ID for the target service group"
},
"msgKey": {
"type": "string",
"description": "Message template key such as sampleText, sampleMarkdown, or another supported DingTalk robot message key"
},
"msgParam": {
"type": "string",
"description": "JSON-encoded message payload string expected by DingTalk for the selected msgKey"
}
},
"additionalProperties": false
}
}
}
}
FILE:references/usage-patterns.md
# DingTalk Messaging Skill - Usage Patterns
## Link Setup
```bash
command -v dingtalk-openapi-cli
uxc link dingtalk-openapi-cli https://api.dingtalk.com/v1.0 \
--schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/dingtalk-openapi-skill/references/dingtalk-messaging.openapi.json
dingtalk-openapi-cli -h
```
## Token Bootstrap
Preferred path: let `uxc` manage app-token bootstrap and refresh from app credentials.
```bash
uxc auth credential set dingtalk-app \
--auth-type bearer \
--field app_key=env:DINGTALK_APP_KEY \
--field app_secret=env:DINGTALK_APP_SECRET
uxc auth bootstrap set dingtalk-app \
--token-endpoint https://api.dingtalk.com/v1.0/oauth2/accessToken \
--header 'Content-Type=application/json' \
--request-json '{"appKey":"{{field:app_key}}","appSecret":"{{field:app_secret}}"}' \
--access-token-pointer /accessToken \
--expires-in-pointer /expireIn
uxc auth bootstrap info dingtalk-app
```
Manual fallback:
```bash
curl -sS https://api.dingtalk.com/v1.0/oauth2/accessToken \
-H 'Content-Type: application/json' \
-d '{"appKey":"dingxxxx","appSecret":"xxxx"}'
```
Store the resulting `accessToken` in an environment variable before binding it into `uxc auth` if you are using the manual fallback.
## Auth Setup
```bash
uxc auth credential set dingtalk-app \
--auth-type bearer \
--secret-env DINGTALK_ACCESS_TOKEN
uxc auth binding add \
--id dingtalk-app \
--host api.dingtalk.com \
--path-prefix /v1.0 \
--scheme https \
--credential dingtalk-app \
--priority 100
```
Validate the binding:
```bash
uxc auth binding match https://api.dingtalk.com/v1.0
```
## Read Examples
```bash
# Read one user by unionId
dingtalk-openapi-cli get:/contact/users/{unionId} unionId=$DINGTALK_UNION_ID
```
## Write Examples (Confirm Intent First)
```bash
# Send a one-to-one bot message to multiple users
dingtalk-openapi-cli post:/robot/oToMessages/batchSend '{"robotCode":"dingxxxx","userIds":["user001","user002"],"msgKey":"sampleText","msgParam":"{\"content\":\"Hello from UXC\"}"}'
# Send a group message through a bot
dingtalk-openapi-cli post:/robot/groupMessages/send '{"openConversationId":"cidxxxx","robotCode":"dingxxxx","msgKey":"sampleText","msgParam":"{\"content\":\"Hello from UXC\"}"}'
# Send a service group message
dingtalk-openapi-cli post:/serviceGroup/messages/send '{"coolAppCode":"coolappxxxx","openConversationId":"cidxxxx","robotCode":"dingxxxx","msgKey":"sampleText","msgParam":"{\"content\":\"Hello from UXC\"}"}'
```
## Fallback Equivalence
- `dingtalk-openapi-cli <operation> ...` is equivalent to
`uxc https://api.dingtalk.com/v1.0 --schema-url <dingtalk_openapi_schema> <operation> ...`.
FILE:scripts/validate.sh
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "BASH_SOURCE[0]")/../../.." && pwd)"
SKILL_DIR="ROOT_DIR/skills/dingtalk-openapi-skill"
SKILL_FILE="SKILL_DIR/SKILL.md"
OPENAI_FILE="SKILL_DIR/agents/openai.yaml"
USAGE_FILE="SKILL_DIR/references/usage-patterns.md"
SCHEMA_FILE="SKILL_DIR/references/dingtalk-messaging.openapi.json"
fail() {
printf '[validate] error: %s\n' "$*" >&2
exit 1
}
need_cmd() {
command -v "$1" >/dev/null 2>&1 || fail "required command not found: $1"
}
need_cmd rg
need_cmd jq
for file in "SKILL_FILE" "OPENAI_FILE" "USAGE_FILE" "SCHEMA_FILE"; do
[[ -f "file" ]] || fail "missing required file: file"
done
jq -e '.openapi and .paths' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'invalid OpenAPI schema JSON or missing .openapi/.paths'
jq -e '.paths["/robot/groupMessages/send"]' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'OpenAPI schema missing /robot/groupMessages/send path'
rg -q '^name:\s*dingtalk-openapi-skill\s*$' "SKILL_FILE" || fail 'invalid skill name'
rg -q '^description:\s*.+' "SKILL_FILE" || fail 'missing description'
rg -q 'command -v dingtalk-openapi-cli' "SKILL_FILE" || fail 'missing link-first command check'
rg -q 'uxc link dingtalk-openapi-cli https://api.dingtalk.com/v1.0 --schema-url ' "SKILL_FILE" || fail 'missing fixed link create command with schema-url'
rg -q 'dingtalk-openapi-cli -h' "SKILL_FILE" || fail 'missing help-first host discovery example'
rg -q 'dingtalk-openapi-cli post:/robot/groupMessages/send -h' "SKILL_FILE" || fail 'missing operation-level help example'
rg -q -- '--auth-type bearer' "SKILL_FILE" || fail 'missing bearer auth setup'
rg -q 'accessToken' "SKILL_FILE" || fail 'missing token bootstrap guidance'
rg -q 'uxc auth binding match https://api.dingtalk.com/v1.0' "SKILL_FILE" || fail 'missing binding match check'
rg -q 'msgParam' "SKILL_FILE" || fail 'missing msgParam guardrail'
rg -q 'high-risk writes' "SKILL_FILE" || fail 'missing write guardrail'
rg -q 'positional JSON' "SKILL_FILE" || fail 'missing positional JSON guidance'
if rg -q -- "--args\\s+'\\{" "SKILL_FILE" "USAGE_FILE"; then
fail 'found banned legacy JSON argument pattern'
fi
rg -q '^\s*display_name:\s*"DingTalk Messaging"\s*$' "OPENAI_FILE" || fail 'missing display_name'
rg -q '^\s*short_description:\s*".+"\s*$' "OPENAI_FILE" || fail 'missing short_description'
rg -q '^\s*default_prompt:\s*".*\$dingtalk-openapi-skill.*"\s*$' "OPENAI_FILE" || fail 'default_prompt must mention $dingtalk-openapi-skill'
echo "skills/dingtalk-openapi-skill validation passed"
Operate Ethereum execution JSON-RPC through UXC with the official execution OpenRPC schema, public EVM read methods, and eth_subscribe pubsub guardrails.
---
name: ethereum-jsonrpc-skill
description: Operate Ethereum execution JSON-RPC through UXC with the official execution OpenRPC schema, public EVM read methods, and eth_subscribe pubsub guardrails.
---
# Ethereum JSON-RPC Skill
Use this skill to run Ethereum execution JSON-RPC operations through `uxc` + JSON-RPC.
Reuse the `uxc` skill for shared execution, auth, and error-handling guidance.
## Prerequisites
- `uxc` is installed and available in `PATH`.
- Network access to a compatible Ethereum execution JSON-RPC provider.
- Access to the official execution OpenRPC schema URL:
- `https://raw.githubusercontent.com/ethereum/execution-apis/assembled-spec/refs-openrpc.json`
## Scope
This skill covers a safe read-first Ethereum execution surface:
- chain identity and public state reads
- block, balance, logs, and call-based state reads
- `eth_subscribe` pubsub subscriptions for new heads, logs, and pending transactions
This skill does **not** cover:
- `eth_sendRawTransaction`
- `personal_*`, `admin_*`, `debug_*`, `engine_*`, `txpool_*`
- wallet signing flows
- private/authenticated RPC providers with custom auth models
## Endpoint And Schema
This skill defaults to a public read provider:
- HTTPS RPC: `https://ethereum-rpc.publicnode.com`
The operation surface comes from the official Ethereum execution OpenRPC schema:
- `https://raw.githubusercontent.com/ethereum/execution-apis/assembled-spec/refs-openrpc.json`
`uxc` JSON-RPC discovery normally depends on OpenRPC or `rpc.discover`. Ethereum RPC providers often do not expose discovery directly, so this skill uses a fixed `--schema-url` link and request flow.
The official execution OpenRPC document is strong enough for normal request/response methods, but it does not currently expose pubsub methods such as `eth_subscribe`. Use the schema-backed link for reads, and use `uxc subscribe start` directly for subscriptions.
For subscriptions, use a WebSocket Ethereum RPC provider that you have verified actually accepts `eth_subscribe`. Do not assume a public HTTPS host automatically guarantees the same `wss://` host is stable for pubsub.
## Authentication
The default public read provider used by this skill does not require authentication.
If a user later points the same workflow at a private Ethereum RPC provider, verify its auth model first before reusing this skill unchanged.
## Core Workflow
1. Use the fixed link command by default:
- `command -v ethereum-jsonrpc-cli`
- If missing, create it:
`uxc link ethereum-jsonrpc-cli https://ethereum-rpc.publicnode.com --schema-url https://raw.githubusercontent.com/ethereum/execution-apis/assembled-spec/refs-openrpc.json`
- `ethereum-jsonrpc-cli -h`
2. Inspect operation schema first:
- `ethereum-jsonrpc-cli eth_blockNumber -h`
- `ethereum-jsonrpc-cli eth_getBlockByNumber -h`
- `ethereum-jsonrpc-cli eth_getBalance -h`
3. Prefer chain and balance/block reads before deeper state queries:
- `ethereum-jsonrpc-cli eth_chainId`
- `ethereum-jsonrpc-cli eth_blockNumber`
- `ethereum-jsonrpc-cli eth_getBalance Address=0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 Block=latest`
4. Execute with key/value or positional JSON:
- key/value:
`ethereum-jsonrpc-cli eth_getBalance Address=0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 Block=latest`
- positional JSON:
`ethereum-jsonrpc-cli eth_getBlockByNumber '["latest", false]'`
- nested positional JSON:
`ethereum-jsonrpc-cli eth_call '[{"to":"0xA0b86991c6218b36c1d19d4a2e9eb0ce3606eb48","data":"0x313ce567"},"latest"]'`
5. Use `uxc subscribe start` directly for pubsub streams:
- `uxc subscribe start wss://<verified-ethereum-rpc-host> eth_subscribe '{"params":["newHeads"]}' --sink file:$HOME/.uxc/subscriptions/eth-new-heads.ndjson`
- `uxc subscribe start wss://<verified-ethereum-rpc-host> eth_subscribe '{"params":["logs",{"address":"0xA0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"}]}' --sink file:$HOME/.uxc/subscriptions/eth-logs.ndjson`
- `uxc subscribe status <job_id>`
- `uxc subscribe stop <job_id>`
## Recommended Read Operations
- `net_version`
- `eth_chainId`
- `eth_blockNumber`
- `eth_getBlockByNumber`
- `eth_getBalance`
- `eth_getLogs`
- `eth_call`
## Recommended Subscription Operations
- `eth_subscribe`
Subscription `params[0]` modes that are usually most useful:
- `newHeads`
- `logs`
- `newPendingTransactions`
## Guardrails
- Keep automation on the JSON output envelope; do not use `--text`.
- Parse stable fields first: `ok`, `kind`, `protocol`, `data`, `error`.
- Stay on read-only methods and `eth_subscribe` by default.
- The official execution OpenRPC schema drives read help and request execution, but it does not cover `eth_subscribe`; treat subscriptions as runtime-only flows, not schema-discovered operations.
- Do not call write/admin/debug/engine methods through this skill without explicit follow-up design and review.
- Use `uxc subscribe start` for pubsub methods; the fixed `ethereum-jsonrpc-cli` link is for normal request/response methods.
- Subscription jobs should always write to a sink file so events can be inspected and replayed safely.
- Before documenting or automating a public Ethereum pubsub host, confirm the specific provider actually exposes WebSocket JSON-RPC subscriptions; public HTTPS endpoints do not guarantee a matching `wss://` endpoint.
- `ethereum-jsonrpc-cli <operation> ...` is equivalent to `uxc https://ethereum-rpc.publicnode.com --schema-url <ethereum_execution_openrpc_schema> <operation> ...`.
## References
- Usage patterns: `references/usage-patterns.md`
- Ethereum execution API specs: https://github.com/ethereum/execution-apis
- Ethereum JSON-RPC overview: https://ethereum.org/developers/docs/apis/json-rpc/
FILE:agents/openai.yaml
display_name: "Ethereum JSON-RPC"
short_description: "Read Ethereum execution RPC and manage eth_subscribe pubsub flows through UXC with the official execution OpenRPC schema."
default_prompt: "Use $ethereum-jsonrpc-skill to discover and execute safe Ethereum execution JSON-RPC reads and eth_subscribe pubsub flows through UXC with the official execution OpenRPC schema, help-first inspection, and sink-based subscription handling."
FILE:references/usage-patterns.md
# Ethereum JSON-RPC Usage Patterns
## Link And Discover
```bash
command -v ethereum-jsonrpc-cli
uxc link ethereum-jsonrpc-cli https://ethereum-rpc.publicnode.com \
--schema-url https://raw.githubusercontent.com/ethereum/execution-apis/assembled-spec/refs-openrpc.json
ethereum-jsonrpc-cli -h
```
## Read Operations
```bash
ethereum-jsonrpc-cli eth_chainId
```
```bash
ethereum-jsonrpc-cli eth_blockNumber
```
```bash
ethereum-jsonrpc-cli eth_getBalance Address=0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 Block=latest
```
```bash
ethereum-jsonrpc-cli eth_getBlockByNumber '["latest", false]'
```
```bash
ethereum-jsonrpc-cli eth_call '[{"to":"0xA0b86991c6218b36c1d19d4a2e9eb0ce3606eb48","data":"0x313ce567"},"latest"]'
```
```bash
ethereum-jsonrpc-cli eth_getLogs '[{"fromBlock":"latest","toBlock":"latest","address":["0xA0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"]}]'
```
## Help-First Checks
```bash
ethereum-jsonrpc-cli eth_blockNumber -h
ethereum-jsonrpc-cli eth_getBlockByNumber -h
ethereum-jsonrpc-cli eth_getBalance -h
```
## Subscription Patterns
Use a WebSocket Ethereum RPC provider you have validated with your provider before automating pubsub. Public HTTPS hosts do not guarantee a matching WebSocket endpoint. `eth_subscribe` is a runtime subscription method and is not described by the current official execution OpenRPC schema.
```bash
uxc subscribe start wss://<verified-ethereum-rpc-host> eth_subscribe \
'{"params":["newHeads"]}' \
--sink file:$HOME/.uxc/subscriptions/eth-new-heads.ndjson
```
```bash
uxc subscribe start wss://<verified-ethereum-rpc-host> eth_subscribe \
'{"params":["logs",{"address":"0xA0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"}]}' \
--sink file:$HOME/.uxc/subscriptions/eth-usdc-logs.ndjson
```
```bash
uxc subscribe status <job_id>
uxc subscribe stop <job_id>
```
## Notes
- `ethereum-jsonrpc-cli <operation> ...` is equivalent to
`uxc https://ethereum-rpc.publicnode.com --schema-url <ethereum_execution_openrpc_schema> <operation> ...`.
- Prefer key/value parameters for simple reads.
- Use bare JSON positional payloads when a method expects nested objects or arrays.
FILE:scripts/validate.sh
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "BASH_SOURCE[0]")/../../.." && pwd)"
SKILL_DIR="ROOT_DIR/skills/ethereum-jsonrpc-skill"
SKILL_FILE="SKILL_DIR/SKILL.md"
OPENAI_FILE="SKILL_DIR/agents/openai.yaml"
USAGE_FILE="SKILL_DIR/references/usage-patterns.md"
fail() {
printf '[validate] error: %s\n' "$*" >&2
exit 1
}
need_cmd() {
command -v "$1" >/dev/null 2>&1 || fail "required command not found: $1"
}
need_cmd rg
for file in "SKILL_FILE" "OPENAI_FILE" "USAGE_FILE"; do
[[ -f "file" ]] || fail "missing required file: file"
done
rg -q '^name:\s*ethereum-jsonrpc-skill\s*$' "SKILL_FILE" || fail 'invalid skill name'
rg -q '^description:\s*.+' "SKILL_FILE" || fail 'missing description'
rg -q 'command -v ethereum-jsonrpc-cli' "SKILL_FILE" || fail 'missing link-first command check'
rg -q 'uxc link ethereum-jsonrpc-cli https://ethereum-rpc.publicnode.com --schema-url https://raw.githubusercontent.com/ethereum/execution-apis/assembled-spec/refs-openrpc.json' "SKILL_FILE" || fail 'missing fixed link create command'
rg -q 'ethereum-jsonrpc-cli -h' "SKILL_FILE" || fail 'missing help-first host discovery example'
rg -q 'ethereum-jsonrpc-cli eth_blockNumber -h' "SKILL_FILE" || fail 'missing operation-level help example'
rg -q 'uxc subscribe start wss://<verified-ethereum-rpc-host> eth_subscribe' "SKILL_FILE" || fail 'missing subscription example'
rg -q 'uxc subscribe stop <job_id>' "SKILL_FILE" || fail 'missing subscribe stop example'
rg -q 'fixed `--schema-url` link' "SKILL_FILE" || fail 'missing schema-url discovery note'
rg -q 'eth_sendRawTransaction' "SKILL_FILE" || fail 'missing write-method guardrail'
rg -q 'positional JSON' "SKILL_FILE" || fail 'missing positional JSON guidance'
rg -q 'validated with your provider' "USAGE_FILE" || fail 'missing provider-validated websocket note'
if rg -q -- '(^|[[:space:]])uxc <host> (list|describe|call)([[:space:]]|$)|(^|[[:space:]])ethereum-jsonrpc-cli (list|describe|call)([[:space:]]|$)|--args .*\{' "SKILL_FILE" "USAGE_FILE"; then
fail 'found banned legacy patterns'
fi
rg -q '^\s*display_name:\s*"Ethereum JSON-RPC"\s*$' "OPENAI_FILE" || fail 'missing display_name'
rg -q '^\s*short_description:\s*".+"\s*$' "OPENAI_FILE" || fail 'missing short_description'
rg -q '^\s*default_prompt:\s*".*\$ethereum-jsonrpc-skill.*"\s*$' "OPENAI_FILE" || fail 'default_prompt must mention $ethereum-jsonrpc-skill'
echo "skills/ethereum-jsonrpc-skill validation passed"
Operate Sui public JSON-RPC through UXC with OpenRPC-driven discovery, mainnet fullnode defaults, and read-only query plus pubsub subscription guardrails.
---
name: sui-jsonrpc-skill
description: Operate Sui public JSON-RPC through UXC with OpenRPC-driven discovery, mainnet fullnode defaults, and read-only query plus pubsub subscription guardrails.
---
# Sui JSON-RPC Skill
Use this skill to run Sui JSON-RPC operations through `uxc` + JSON-RPC.
Reuse the `uxc` skill for shared execution and error-handling guidance.
## Prerequisites
- `uxc` is installed and available in `PATH`.
- Network access to `https://fullnode.mainnet.sui.io`.
- No API key is required for the public mainnet fullnode in this skill's default flow.
## Scope
This skill covers a safe read-first Sui JSON-RPC surface:
- chain identity and latest checkpoint reads
- checkpoint lookup
- object lookup
- reference gas price reads
- latest system state reads
- pubsub subscriptions for events and transaction effects
This skill does **not** cover:
- `unsafe_*` transaction-building methods
- `sui_executeTransactionBlock`
- wallet signing flows
- custom/private Sui RPC providers with different auth or rate limits
## Endpoint And Discovery
This skill targets the public Sui fullnode endpoint:
- `https://fullnode.mainnet.sui.io`
For pubsub, use a Sui provider WebSocket endpoint that you have verified actually accepts JSON-RPC subscriptions. Do not assume the public HTTPS fullnode host automatically supports the same `wss://` hostname for pubsub.
`uxc` JSON-RPC discovery depends on OpenRPC or `rpc.discover`. Sui exposes a discoverable method surface, so help-first flow works directly against the endpoint.
## Authentication
The default public endpoint used by this skill does not require authentication.
If a user later points the same workflow at a private Sui RPC provider, verify its auth model first before reusing this skill unchanged.
## Core Workflow
1. Use the fixed link command by default:
- `command -v sui-jsonrpc-cli`
- If missing, create it:
`uxc link sui-jsonrpc-cli https://fullnode.mainnet.sui.io`
- `sui-jsonrpc-cli -h`
2. Inspect operation schema first:
- `sui-jsonrpc-cli sui_getLatestCheckpointSequenceNumber -h`
- `sui-jsonrpc-cli sui_getCheckpoint -h`
- `sui-jsonrpc-cli sui_getObject -h`
3. Prefer read/setup validation before any deeper query:
- `sui-jsonrpc-cli sui_getChainIdentifier`
- `sui-jsonrpc-cli sui_getLatestCheckpointSequenceNumber`
- `sui-jsonrpc-cli suix_getReferenceGasPrice`
4. Execute with key/value or positional JSON:
- key/value:
`sui-jsonrpc-cli sui_getCheckpoint id=254502592`
- positional JSON:
`sui-jsonrpc-cli sui_getObject '{"object_id":"0x6"}'`
5. Use `uxc subscribe start` directly for pubsub streams:
- `uxc subscribe start wss://<verified-sui-rpc-host> suix_subscribeEvent '{"params":[{"Package":"0x2"}]}' --sink file:$HOME/.uxc/subscriptions/sui-events.ndjson`
- `uxc subscribe start wss://<verified-sui-rpc-host> suix_subscribeTransaction '{"params":[{"FromAddress":"0x..."}]}' --sink file:$HOME/.uxc/subscriptions/sui-transactions.ndjson`
- `uxc subscribe status <job_id>`
- `uxc subscribe stop <job_id>`
## Recommended Read Operations
- `sui_getChainIdentifier`
- `sui_getLatestCheckpointSequenceNumber`
- `sui_getCheckpoint`
- `sui_getObject`
- `suix_getReferenceGasPrice`
- `suix_getLatestSuiSystemState`
## Recommended Subscription Operations
- `suix_subscribeEvent`
- `suix_subscribeTransaction`
## Guardrails
- Keep automation on the JSON output envelope; do not use `--text`.
- Parse stable fields first: `ok`, `kind`, `protocol`, `data`, `error`.
- Stay on the public read-only method surface by default.
- Do not call any `unsafe_*` methods through this skill without explicit follow-up design and review.
- Do not use this skill for write/sign/submit flows; those need separate wallet/auth guidance.
- Use `uxc subscribe start` for pubsub methods; the fixed `sui-jsonrpc-cli` link is for normal request/response methods.
- Subscription jobs should always write to a sink file so events can be inspected and replayed safely.
- Before documenting or automating a Sui pubsub host, confirm the specific provider actually exposes JSON-RPC WebSocket subscriptions; public HTTPS endpoints do not guarantee a matching `wss://` endpoint.
- Public RPC availability and rate limits can change over time; if discovery or execution starts failing, re-check the endpoint before assuming a `uxc` bug.
- `sui-jsonrpc-cli <operation> ...` is equivalent to `uxc https://fullnode.mainnet.sui.io <operation> ...`.
## References
- Usage patterns: `references/usage-patterns.md`
- Sui documentation: https://docs.sui.io/
FILE:agents/openai.yaml
interface:
display_name: "Sui JSON-RPC"
short_description: "Read Sui mainnet chain data and run Sui pubsub subscriptions through UXC"
default_prompt: "Use $sui-jsonrpc-skill to discover and execute safe Sui JSON-RPC reads and pubsub subscriptions through UXC with help-first OpenRPC discovery, public fullnode defaults, and sink-based subscription handling."
FILE:references/usage-patterns.md
# Sui JSON-RPC Skill - Usage Patterns
## Link Setup
```bash
command -v sui-jsonrpc-cli
uxc link sui-jsonrpc-cli https://fullnode.mainnet.sui.io
sui-jsonrpc-cli -h
```
## Read Examples
```bash
# Read the chain identifier
sui-jsonrpc-cli sui_getChainIdentifier
# Read the latest executed checkpoint sequence number
sui-jsonrpc-cli sui_getLatestCheckpointSequenceNumber
# Read one checkpoint by sequence number
sui-jsonrpc-cli sui_getCheckpoint id=254502592
# Read the current reference gas price
sui-jsonrpc-cli suix_getReferenceGasPrice
# Read the latest system state
sui-jsonrpc-cli suix_getLatestSuiSystemState
```
## Object Lookup Examples
```bash
# Read an object by id using key=value input
sui-jsonrpc-cli sui_getObject object_id=0x6
# Read an object by id using positional JSON
sui-jsonrpc-cli sui_getObject '{"object_id":"0x6"}'
```
## Help-First Examples
```bash
sui-jsonrpc-cli sui_getLatestCheckpointSequenceNumber -h
sui-jsonrpc-cli sui_getCheckpoint -h
sui-jsonrpc-cli sui_getObject -h
sui-jsonrpc-cli suix_subscribeEvent -h
```
## Subscription Examples
```bash
# Subscribe to events from a package and write NDJSON to a sink file
uxc subscribe start \
wss://<verified-sui-rpc-host> \
suix_subscribeEvent \
'{"params":[{"Package":"0x2"}]}' \
--sink file:$HOME/.uxc/subscriptions/sui-events.ndjson
# Subscribe to transaction effects that match a filter
uxc subscribe start \
wss://<verified-sui-rpc-host> \
suix_subscribeTransaction \
'{"params":[{"FromAddress":"0x0000000000000000000000000000000000000000000000000000000000000000"}]}' \
--sink file:$HOME/.uxc/subscriptions/sui-transactions.ndjson
# Inspect and stop a running job
uxc subscribe status <job_id>
uxc subscribe stop <job_id>
```
Use a WebSocket endpoint you have validated with your Sui provider; do not assume the public HTTPS fullnode host automatically maps to a working `wss://` pubsub endpoint.
## Fallback Equivalence
- `sui-jsonrpc-cli <operation> ...` is equivalent to
`uxc https://fullnode.mainnet.sui.io <operation> ...`.
FILE:scripts/validate.sh
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "BASH_SOURCE[0]")/../../.." && pwd)"
SKILL_DIR="ROOT_DIR/skills/sui-jsonrpc-skill"
SKILL_FILE="SKILL_DIR/SKILL.md"
OPENAI_FILE="SKILL_DIR/agents/openai.yaml"
USAGE_FILE="SKILL_DIR/references/usage-patterns.md"
fail() {
printf '[validate] error: %s\n' "$*" >&2
exit 1
}
need_cmd() {
command -v "$1" >/dev/null 2>&1 || fail "required command not found: $1"
}
need_cmd rg
for file in "SKILL_FILE" "OPENAI_FILE" "USAGE_FILE"; do
[[ -f "file" ]] || fail "missing required file: file"
done
rg -q '^name:\s*sui-jsonrpc-skill\s*$' "SKILL_FILE" || fail 'invalid skill name'
rg -q '^description:\s*.+' "SKILL_FILE" || fail 'missing description'
rg -q 'command -v sui-jsonrpc-cli' "SKILL_FILE" || fail 'missing link-first command check'
rg -q 'uxc link sui-jsonrpc-cli https://fullnode.mainnet.sui.io' "SKILL_FILE" || fail 'missing fixed link create command'
rg -q 'sui-jsonrpc-cli -h' "SKILL_FILE" || fail 'missing help-first host discovery example'
rg -q 'sui-jsonrpc-cli sui_getLatestCheckpointSequenceNumber -h' "SKILL_FILE" || fail 'missing operation-level help example'
rg -q 'uxc subscribe start wss://<verified-sui-rpc-host> suix_subscribeEvent' "SKILL_FILE" || fail 'missing event subscription example'
rg -q 'uxc subscribe stop <job_id>' "SKILL_FILE" || fail 'missing subscribe stop example'
rg -q 'OpenRPC or `rpc.discover`' "SKILL_FILE" || fail 'missing JSON-RPC discovery note'
rg -q 'unsafe_\*' "SKILL_FILE" || fail 'missing unsafe method guardrail'
rg -q 'positional JSON' "SKILL_FILE" || fail 'missing positional JSON guidance'
rg -q 'Use `uxc subscribe start` for pubsub methods' "SKILL_FILE" || fail 'missing pubsub execution guidance'
rg -q 'validated with your Sui provider' "USAGE_FILE" || fail 'missing provider-verified websocket endpoint note'
if rg -q -- '(^|[[:space:]])uxc <host> (list|describe|call)([[:space:]]|$)|(^|[[:space:]])sui-jsonrpc-cli (list|describe|call)([[:space:]]|$)|--args .*\{' "SKILL_FILE" "USAGE_FILE"; then
fail 'found banned legacy patterns'
fi
rg -q '^\s*display_name:\s*"Sui JSON-RPC"\s*$' "OPENAI_FILE" || fail 'missing display_name'
rg -q '^\s*short_description:\s*".+"\s*$' "OPENAI_FILE" || fail 'missing short_description'
rg -q '^\s*default_prompt:\s*".*\$sui-jsonrpc-skill.*"\s*$' "OPENAI_FILE" || fail 'default_prompt must mention $sui-jsonrpc-skill'
echo "skills/sui-jsonrpc-skill validation passed"
Subscribe to OKX public exchange WebSocket channels through UXC raw WebSocket mode for ticker, trade, book, and candle events with explicit subscribe frames.
---
name: okx-exchange-websocket-skill
description: Subscribe to OKX public exchange WebSocket channels through UXC raw WebSocket mode for ticker, trade, book, and candle events with explicit subscribe frames.
---
# OKX Exchange WebSocket Skill
Use this skill to run OKX public exchange WebSocket channels through `uxc subscribe` raw WebSocket mode.
Reuse the `uxc` skill for generic runtime behavior, sink handling, and event-envelope parsing.
## Prerequisites
- `uxc` is installed and available in `PATH`.
- Network access to the OKX public WebSocket endpoint.
- A writable sink path for NDJSON output.
## Scope
This skill covers OKX public exchange channels such as:
- tickers
- trades
- books and books5
- candle channels
This skill does **not** cover:
- OKX OnchainOS MCP
- private WebSocket login flows
- trading, account, or order-management channels
- REST API workflows
## Endpoint Model
Use the OKX public WebSocket endpoint:
- `wss://ws.okx.com:8443/ws/v5/public`
OKX public channels require a subscribe frame after connect, for example:
```json
{"op":"subscribe","args":[{"channel":"tickers","instId":"BTC-USDT"}]}
```
## Core Workflow
1. Start a raw WebSocket subscription:
- `uxc subscribe start wss://ws.okx.com:8443/ws/v5/public --transport websocket --init-frame '{"op":"subscribe","args":[{"channel":"tickers","instId":"BTC-USDT"}]}' --sink file:$HOME/.uxc/subscriptions/okx-btcusdt-ticker.ndjson`
2. Inspect sink output:
- `tail -n 5 $HOME/.uxc/subscriptions/okx-btcusdt-ticker.ndjson`
3. Query runtime status:
- `uxc subscribe list`
- `uxc subscribe status <job_id>`
4. Stop the job when finished:
- `uxc subscribe stop <job_id>`
## Common Subscribe Frames
- tickers:
- `{"op":"subscribe","args":[{"channel":"tickers","instId":"BTC-USDT"}]}`
- trades:
- `{"op":"subscribe","args":[{"channel":"trades","instId":"BTC-USDT"}]}`
- books5:
- `{"op":"subscribe","args":[{"channel":"books5","instId":"BTC-USDT"}]}`
- candles:
- `{"op":"subscribe","args":[{"channel":"candle1m","instId":"BTC-USDT"}]}`
## Runtime Validation
The following live raw WebSocket flow has been validated successfully through `uxc`:
- endpoint: `wss://ws.okx.com:8443/ws/v5/public`
- transport: `--transport websocket`
- init frame:
- `{"op":"subscribe","args":[{"channel":"tickers","instId":"BTC-USDT"}]}`
Observed sink behavior:
- initial `open`
- JSON `data` event for subscription acknowledgement
- repeated `data` events carrying ticker payloads under:
- `arg.channel`
- `arg.instId`
- `data[0].last`
- `data[0].bidPx`
- `data[0].askPx`
- `data[0].ts`
## Guardrails
- Keep automation on the JSON output envelope; do not use `--text`.
- Parse stable event fields first: `event_kind`, `data`, `meta`.
- Always pass `--transport websocket` for this skill.
- Public OKX channels do not require login. Do not mix this skill with private WebSocket auth flows.
- `--init-frame` is required because OKX public channels are multiplexed behind one endpoint.
- `instId` values use OKX instrument naming such as `BTC-USDT`.
- `uxc subscribe start ... --transport websocket` is the intended execution path for this skill; `uxc link` is not the main interface because channel selection lives in the subscribe frame.
## References
- Usage patterns:
- `references/usage-patterns.md`
- OKX WebSocket API:
- https://www.okx.com/docs-v5/en/
FILE:agents/openai.yaml
interface:
display_name: "OKX Exchange WebSocket"
short_description: "Public OKX exchange channels via raw WebSocket subscribe"
default_prompt: "Use $okx-exchange-websocket-skill to subscribe to OKX public exchange WebSocket channels through UXC raw WebSocket mode with explicit subscribe frames."
FILE:references/usage-patterns.md
# Usage Patterns
This skill uses raw WebSocket subscriptions through `uxc subscribe start` with explicit OKX subscribe frames.
## Ticker Channel
```bash
uxc subscribe start \
wss://ws.okx.com:8443/ws/v5/public \
--transport websocket \
--init-frame '{"op":"subscribe","args":[{"channel":"tickers","instId":"BTC-USDT"}]}' \
--sink file:$HOME/.uxc/subscriptions/okx-btcusdt-ticker.ndjson
```
## Trades Channel
```bash
uxc subscribe start \
wss://ws.okx.com:8443/ws/v5/public \
--transport websocket \
--init-frame '{"op":"subscribe","args":[{"channel":"trades","instId":"BTC-USDT"}]}' \
--sink file:$HOME/.uxc/subscriptions/okx-btcusdt-trades.ndjson
```
## Books5 Channel
```bash
uxc subscribe start \
wss://ws.okx.com:8443/ws/v5/public \
--transport websocket \
--init-frame '{"op":"subscribe","args":[{"channel":"books5","instId":"BTC-USDT"}]}' \
--sink file:$HOME/.uxc/subscriptions/okx-btcusdt-books5.ndjson
```
## Runtime Inspection
```bash
uxc subscribe list
uxc subscribe status sub_123
uxc subscribe stop sub_123
```
## Notes
- `--init-frame` is required for channel selection.
- Subscription acknowledgements arrive as normal JSON `data` events.
- Realtime payloads also arrive as JSON `data` events in the same sink.
FILE:scripts/validate.sh
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "BASH_SOURCE[0]")/../../.." && pwd)"
SKILL_DIR="ROOT_DIR/skills/okx-exchange-websocket-skill"
SKILL_FILE="SKILL_DIR/SKILL.md"
OPENAI_FILE="SKILL_DIR/agents/openai.yaml"
USAGE_FILE="SKILL_DIR/references/usage-patterns.md"
fail() {
printf '[validate] error: %s\n' "$*" >&2
exit 1
}
command -v rg >/dev/null 2>&1 || fail "required command not found: rg"
for file in "SKILL_FILE" "OPENAI_FILE" "USAGE_FILE" "SKILL_DIR/scripts/validate.sh"; do
[[ -f "file" ]] || fail "missing required file: file"
done
rg -q '^name:\s*okx-exchange-websocket-skill\s*$' "SKILL_FILE" || fail 'invalid skill name'
rg -q '^description:\s*.+' "SKILL_FILE" || fail 'missing description'
rg -q 'wss://ws\.okx\.com:8443/ws/v5/public' "SKILL_FILE" "USAGE_FILE" || fail 'missing OKX public websocket endpoint'
rg -q 'uxc subscribe start' "SKILL_FILE" "USAGE_FILE" || fail 'missing subscribe start command'
rg -q -- '--transport websocket' "SKILL_FILE" "USAGE_FILE" || fail 'missing raw websocket transport guidance'
rg -q -- '--init-frame' "SKILL_FILE" "USAGE_FILE" || fail 'missing init frame guidance'
rg -q '"channel":"tickers"' "SKILL_FILE" "USAGE_FILE" || fail 'missing ticker subscribe example'
if rg -q -- '--input-json' "SKILL_FILE" "USAGE_FILE"; then
fail 'found banned legacy or misleading command pattern'
fi
if rg -q -- "--args\\s+'\\{" "SKILL_FILE" "USAGE_FILE"; then
fail 'found banned legacy JSON argument pattern'
fi
rg -q '^\s*display_name:\s*"OKX Exchange WebSocket"\s*$' "OPENAI_FILE" || fail 'missing display_name'
rg -q '^\s*short_description:\s*".+"\s*$' "OPENAI_FILE" || fail 'missing short_description'
rg -q '^\s*default_prompt:\s*".*\$okx-exchange-websocket-skill.*"\s*$' "OPENAI_FILE" || fail 'default_prompt must mention $okx-exchange-websocket-skill'
echo "skills/okx-exchange-websocket-skill validation passed"
Subscribe to Binance Spot public market streams through UXC raw WebSocket support for trades, book ticker, depth, and ticker events with stream-specific guar...
---
name: binance-spot-websocket-skill
description: Subscribe to Binance Spot public market streams through UXC raw WebSocket support for trades, book ticker, depth, and ticker events with stream-specific guardrails.
---
# Binance Spot WebSocket Skill
Use this skill to run Binance Spot public market streams through `uxc subscribe` raw WebSocket mode.
Reuse the `uxc` skill for generic runtime behavior, sink handling, and event-envelope parsing.
## Prerequisites
- `uxc` is installed and available in `PATH`.
- Network access to Binance Spot public WebSocket streams.
- A writable sink path for NDJSON output.
## Scope
This skill covers Binance Spot public market streams such as:
- trade events
- aggregate trade events
- book ticker updates
- ticker updates
- depth updates
This skill does **not** cover:
- Binance Spot REST/OpenAPI workflows
- private user data streams
- signed WebSocket API methods
- margin, wallet, futures, or other non-Spot product families
## Endpoint Model
Binance Spot public market streams use raw WebSocket endpoints.
- preferred base: `wss://stream.binance.com:443`
- raw stream form: `wss://stream.binance.com:443/ws/<streamName>`
- combined stream form: `wss://stream.binance.com:443/stream?streams=<stream1>/<stream2>`
Important:
- stream names are lowercase
- connections are valid for up to 24 hours
- raw stream payloads arrive directly as JSON objects
- combined stream payloads arrive as `{"stream":"...","data":{...}}`
## Core Workflow
1. Start a subscription directly with `uxc subscribe start`:
- `uxc subscribe start wss://stream.binance.com:443/ws/btcusdt@trade --transport websocket --sink file:$HOME/.uxc/subscriptions/binance-btcusdt-trade.ndjson`
2. Inspect the sink output:
- `tail -n 5 $HOME/.uxc/subscriptions/binance-btcusdt-trade.ndjson`
3. Query runtime status:
- `uxc subscribe list`
- `uxc subscribe status <job_id>`
4. Stop the job when finished:
- `uxc subscribe stop <job_id>`
## Common Stream Targets
- raw trade stream:
- `btcusdt@trade`
- aggregate trade stream:
- `btcusdt@aggTrade`
- book ticker stream:
- `btcusdt@bookTicker`
- mini ticker stream:
- `btcusdt@miniTicker`
- rolling ticker stream:
- `btcusdt@ticker`
- depth stream:
- `btcusdt@depth`
## Runtime Validation
The following live raw WebSocket flow was validated successfully through `uxc`:
- endpoint: `wss://stream.binance.com:443/ws/btcusdt@trade`
- transport: `--transport websocket`
- sink output:
- `open`
- repeated `data` events with Binance `trade` payloads
- `closed` after stop
Observed event fields included:
- `e: "trade"`
- `s: "BTCUSDT"`
- `p`
- `q`
- `t`
## Guardrails
- Keep automation on the JSON output envelope; do not use `--text`.
- Parse stable event fields first: `event_kind`, `data`, `meta`.
- Use `wss://stream.binance.com:443` as the default public stream host; it validated more reliably than `:9443` in recent runtime checks.
- Stream names must be lowercase.
- This skill is read-only. Do not describe it as account, order, or signed WebSocket support.
- Combined streams are useful when one job should emit multiple markets into one sink, but downstream parsing must handle `stream` wrappers.
- `uxc subscribe start ... --transport websocket` is the intended execution path for this skill; `uxc link` is not the main interface because stream identity is encoded directly in the endpoint path.
## References
- Usage patterns:
- `references/usage-patterns.md`
- Binance Spot WebSocket Streams:
- https://developers.binance.com/docs/binance-spot-api-docs/web-socket-streams
FILE:agents/openai.yaml
interface:
display_name: "Binance Spot WebSocket"
short_description: "Public Binance Spot market streams via raw WebSocket subscribe"
default_prompt: "Use $binance-spot-websocket-skill to subscribe to Binance Spot public market streams through UXC raw WebSocket mode with sink-based event handling."
FILE:references/usage-patterns.md
# Usage Patterns
This skill uses raw WebSocket subscriptions through `uxc subscribe start`.
## Trade Stream
```bash
uxc subscribe start \
wss://stream.binance.com:443/ws/btcusdt@trade \
--transport websocket \
--sink file:$HOME/.uxc/subscriptions/binance-btcusdt-trade.ndjson
```
## Aggregate Trade Stream
```bash
uxc subscribe start \
wss://stream.binance.com:443/ws/btcusdt@aggTrade \
--transport websocket \
--sink file:$HOME/.uxc/subscriptions/binance-btcusdt-aggtrade.ndjson
```
## Book Ticker Stream
```bash
uxc subscribe start \
wss://stream.binance.com:443/ws/btcusdt@bookTicker \
--transport websocket \
--sink file:$HOME/.uxc/subscriptions/binance-btcusdt-bookticker.ndjson
```
## Combined Stream
```bash
uxc subscribe start \
'wss://stream.binance.com:443/stream?streams=btcusdt@trade/ethusdt@trade' \
--transport websocket \
--sink file:$HOME/.uxc/subscriptions/binance-combined.ndjson
```
## Runtime Inspection
```bash
uxc subscribe list
uxc subscribe status sub_123
uxc subscribe stop sub_123
```
## Notes
- Binance stream names are lowercase.
- `uxc subscribe start ... --transport websocket` is the canonical execution path for this skill.
- Raw stream payloads arrive directly as market-event JSON.
- Combined stream payloads wrap each message with `stream` and `data`.
FILE:scripts/validate.sh
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "BASH_SOURCE[0]")/../../.." && pwd)"
SKILL_DIR="ROOT_DIR/skills/binance-spot-websocket-skill"
SKILL_FILE="SKILL_DIR/SKILL.md"
OPENAI_FILE="SKILL_DIR/agents/openai.yaml"
USAGE_FILE="SKILL_DIR/references/usage-patterns.md"
fail() {
printf '[validate] error: %s\n' "$*" >&2
exit 1
}
command -v rg >/dev/null 2>&1 || fail "required command not found: rg"
for file in "SKILL_FILE" "OPENAI_FILE" "USAGE_FILE" "SKILL_DIR/scripts/validate.sh"; do
[[ -f "file" ]] || fail "missing required file: file"
done
rg -q '^name:\s*binance-spot-websocket-skill\s*$' "SKILL_FILE" || fail 'invalid skill name'
rg -q '^description:\s*.+' "SKILL_FILE" || fail 'missing description'
rg -q 'wss://stream\.binance\.com:443' "SKILL_FILE" "USAGE_FILE" || fail 'missing Binance stream endpoint'
rg -q 'uxc subscribe start' "SKILL_FILE" "USAGE_FILE" || fail 'missing subscribe start command'
rg -q -- '--transport websocket' "SKILL_FILE" "USAGE_FILE" || fail 'missing raw websocket transport guidance'
rg -q 'btcusdt@trade' "SKILL_FILE" "USAGE_FILE" || fail 'missing validated trade stream example'
rg -q 'lowercase' "SKILL_FILE" "USAGE_FILE" || fail 'missing lowercase stream guardrail'
if rg -q -- '--input-json' "SKILL_FILE" "USAGE_FILE"; then
fail 'found banned legacy or misleading command pattern'
fi
if rg -q -- "--args\\s+'\\{" "SKILL_FILE" "USAGE_FILE"; then
fail 'found banned legacy JSON argument pattern'
fi
rg -q '^\s*display_name:\s*"Binance Spot WebSocket"\s*$' "OPENAI_FILE" || fail 'missing display_name'
rg -q '^\s*short_description:\s*".+"\s*$' "OPENAI_FILE" || fail 'missing short_description'
rg -q '^\s*default_prompt:\s*".*\$binance-spot-websocket-skill.*"\s*$' "OPENAI_FILE" || fail 'default_prompt must mention $binance-spot-websocket-skill'
echo "skills/binance-spot-websocket-skill validation passed"
Operate Feishu or Lark IM APIs through UXC with a curated OpenAPI schema, tenant-token bearer auth, and chat/message guardrails.
---
name: feishu-openapi-skill
description: Operate Feishu or Lark IM APIs through UXC with a curated OpenAPI schema, tenant-token bearer auth, and chat/message guardrails.
---
# Feishu / Lark IM Skill
Use this skill to run Feishu or Lark IM operations through `uxc` + OpenAPI.
Reuse the `uxc` skill for shared execution, auth, and error-handling guidance.
## Prerequisites
- `uxc` is installed and available in `PATH`.
- Network access to `https://open.feishu.cn/open-apis` or `https://open.larksuite.com/open-apis`.
- Access to the curated OpenAPI schema URL:
- `https://raw.githubusercontent.com/holon-run/uxc/main/skills/feishu-openapi-skill/references/feishu-im.openapi.json`
- A Feishu or Lark app with bot capability enabled.
- A Feishu or Lark app `app_id` + `app_secret`, or a current `tenant_access_token` if you are using the manual fallback path.
## Scope
This skill covers an IM-focused request/response surface:
- chat lookup
- chat member lookup
- image and file upload for IM sends
- message send and reply
- selected message history reads
- basic user lookup through contact APIs
This skill does **not** cover:
- docs, bitable, approval, or non-IM product families
- the full Feishu or Lark Open Platform surface
## Subscribe Status
Feishu and Lark expose event-delivery models beyond plain request/response APIs, including long-connection event delivery in the platform ecosystem.
Current `uxc subscribe` status:
- request/response IM operations are validated
- inbound message intake is validated through the built-in `feishu-long-connection` transport
- live validation confirmed real `im.message.receive_v1` events delivered into the subscribe sink for a `p2p` bot chat
Important runtime notes:
- `feishu-long-connection` is a provider-aware transport inside `uxc subscribe`; it is not a plain raw WebSocket stream
- the runtime opens a temporary WebSocket URL from `/callback/ws/endpoint`
- frames are protobuf binary messages, not text JSON
- the runtime sends required event acknowledgements and ping control frames automatically
## Endpoint Choice
This schema works against either Feishu or Lark Open Platform base URLs:
- China / Feishu default: `https://open.feishu.cn/open-apis`
- International / Lark alternative: `https://open.larksuite.com/open-apis`
The fixed link example below uses Feishu. For Lark, use the same schema URL against the Lark base host.
## Authentication
Feishu and Lark service-side APIs use `Authorization: Bearer <tenant_access_token>` for these operations.
Preferred setup is to store `app_id` + `app_secret` as credential fields and let `uxc auth bootstrap` fetch and refresh the short-lived tenant token automatically.
Feishu bootstrap-managed setup:
```bash
uxc auth credential set feishu-tenant \
--auth-type bearer \
--field app_id=env:FEISHU_APP_ID \
--field app_secret=env:FEISHU_APP_SECRET
uxc auth bootstrap set feishu-tenant \
--token-endpoint https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal \
--header 'Content-Type=application/json; charset=utf-8' \
--request-json '{"app_id":"{{field:app_id}}","app_secret":"{{field:app_secret}}"}' \
--access-token-pointer /tenant_access_token \
--expires-in-pointer /expire \
--success-code-pointer /code \
--success-code-value 0
uxc auth binding add \
--id feishu-tenant \
--host open.feishu.cn \
--path-prefix /open-apis \
--scheme https \
--credential feishu-tenant \
--priority 100
```
For Lark, use the same bootstrap shape against the Lark host and bind the credential to `open.larksuite.com`.
To use long-connection subscribe, the credential still needs `app_id` and `app_secret` fields because the transport opens its own temporary event URL outside the normal bearer-token request path.
Manual fallback if you already have a tenant token:
```bash
curl -sS https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal \
-H 'Content-Type: application/json; charset=utf-8' \
-d '{"app_id":"cli_xxx","app_secret":"xxxx"}'
```
Lark uses the same path shape on the Lark host:
```bash
curl -sS https://open.larksuite.com/open-apis/auth/v3/tenant_access_token/internal \
-H 'Content-Type: application/json; charset=utf-8' \
-d '{"app_id":"cli_xxx","app_secret":"xxxx"}'
```
Configure one bearer credential and bind it to the Feishu API host:
```bash
uxc auth credential set feishu-tenant \
--auth-type bearer \
--secret-env FEISHU_TENANT_ACCESS_TOKEN
uxc auth binding add \
--id feishu-tenant \
--host open.feishu.cn \
--path-prefix /open-apis \
--scheme https \
--credential feishu-tenant \
--priority 100
```
For Lark, create the same binding against `open.larksuite.com`:
```bash
uxc auth binding add \
--id lark-tenant \
--host open.larksuite.com \
--path-prefix /open-apis \
--scheme https \
--credential feishu-tenant \
--priority 100
```
Inspect or pre-warm bootstrap state when auth looks wrong:
```bash
uxc auth bootstrap info feishu-tenant
uxc auth bootstrap refresh feishu-tenant
```
Validate the active binding when auth looks wrong:
```bash
uxc auth binding match https://open.feishu.cn/open-apis
```
## Core Workflow
1. Use the fixed link command by default:
- `command -v feishu-openapi-cli`
- If missing, create it:
`uxc link feishu-openapi-cli https://open.feishu.cn/open-apis --schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/feishu-openapi-skill/references/feishu-im.openapi.json`
- `feishu-openapi-cli -h`
2. Inspect operation schema first:
- `feishu-openapi-cli get:/im/v1/chats -h`
- `feishu-openapi-cli post:/im/v1/images -h`
- `feishu-openapi-cli post:/im/v1/files -h`
- `feishu-openapi-cli post:/im/v1/messages -h`
- `feishu-openapi-cli get:/im/v1/messages -h`
3. Prefer read/setup validation before writes:
- `feishu-openapi-cli get:/im/v1/chats page_size=20`
- `feishu-openapi-cli get:/im/v1/chats/{chat_id} chat_id=oc_xxx`
- `feishu-openapi-cli get:/contact/v3/users/{user_id} user_id=ou_xxx user_id_type=open_id`
4. Execute with key/value or positional JSON:
- key/value:
`feishu-openapi-cli get:/im/v1/messages container_id_type=chat container_id=oc_xxx page_size=20`
- multipart upload:
`feishu-openapi-cli post:/im/v1/images image_type=message image=/tmp/example.png`
- positional JSON:
`feishu-openapi-cli post:/im/v1/messages receive_id_type=chat_id '{"receive_id":"oc_xxx","msg_type":"text","content":"{\"text\":\"Hello from UXC\"}"}'`
5. For inbound message intake, use `uxc subscribe` directly:
- `uxc subscribe start https://open.feishu.cn/open-apis --transport feishu-long-connection --auth feishu-tenant --sink file:$HOME/.uxc/subscriptions/feishu.ndjson`
- send a bot-visible message, then inspect the sink for `header.event_type = "im.message.receive_v1"`
## Operation Groups
### Chat Reads
- `get:/im/v1/chats`
- `get:/im/v1/chats/{chat_id}`
- `get:/im/v1/chats/{chat_id}/members`
### Message Reads / Writes
- `get:/im/v1/messages`
- `get:/im/v1/messages/{message_id}`
- `post:/im/v1/messages`
- `post:/im/v1/messages/{message_id}/reply`
### Uploads
- `post:/im/v1/images`
- `post:/im/v1/files`
### User Lookup
- `get:/contact/v3/users/{user_id}`
- `post:/contact/v3/users/batch_get_id`
## Guardrails
- Keep automation on the JSON output envelope; do not use `--text`.
- Parse stable fields first: `ok`, `kind`, `protocol`, `data`, `error`.
- Prefer `uxc auth bootstrap` over manual token management. Manual `tenant_access_token` setup is still supported as a fallback.
- `feishu-long-connection` requires the app credential fields `app_id` and `app_secret`; a plain bearer-only credential is not enough for event intake.
- `post:/im/v1/images` and `post:/im/v1/files` use `multipart/form-data`. File fields must be local path strings; help output marks them as multipart file fields.
- `post:/im/v1/messages` requires the `receive_id_type` query parameter and the body `content` field is a JSON-encoded string, not a nested JSON object.
- Upload first, then send by returned key:
- image sends use `msg_type=image` with `content='{\"image_key\":\"img_xxx\"}'`
- file sends use `msg_type=file` with `content='{\"file_key\":\"file_xxx\"}'`
- `post:/im/v1/messages/{message_id}/reply` is for explicit replies to an existing message. Treat it as a high-risk write.
- History reads only return chats and messages visible to the bot/app configuration. Auth success does not imply access to every chat.
- Long-connection message intake is validated for Feishu bot chats; webhook-style callbacks and non-IM products are still out of scope.
- `feishu-openapi-cli <operation> ...` is equivalent to `uxc https://open.feishu.cn/open-apis --schema-url <feishu_openapi_schema> <operation> ...`.
## References
- Usage patterns: `references/usage-patterns.md`
- Curated OpenAPI schema: `references/feishu-im.openapi.json`
- Feishu Open Platform docs: https://open.feishu.cn/document/
- Lark Open Platform docs: https://open.larksuite.com/document/
FILE:agents/openai.yaml
interface:
display_name: "Feishu / Lark IM"
short_description: "Operate Feishu or Lark IM APIs via UXC + curated OpenAPI schema"
default_prompt: "Use $feishu-openapi-skill to discover and execute Feishu or Lark IM operations through UXC with tenant-token bearer auth, chat/message scope, and content-string guardrails."
FILE:references/feishu-im.openapi.json
{
"openapi": "3.0.3",
"info": {
"title": "Feishu / Lark IM API (Curated)",
"version": "1.0.0",
"description": "Curated Feishu / Lark IM and contact surface for UXC messaging workflows."
},
"servers": [
{
"url": "https://open.feishu.cn/open-apis"
},
{
"url": "https://open.larksuite.com/open-apis"
}
],
"security": [
{
"FeishuBearerAuth": []
}
],
"paths": {
"/im/v1/chats": {
"get": {
"summary": "List chats visible to the app",
"parameters": [
{
"name": "page_size",
"in": "query",
"required": false,
"schema": {
"type": "integer",
"minimum": 1,
"maximum": 100
},
"description": "Number of chats to return"
},
{
"name": "page_token",
"in": "query",
"required": false,
"schema": {
"type": "string"
},
"description": "Pagination token from a previous response"
},
{
"name": "sort_type",
"in": "query",
"required": false,
"schema": {
"type": "string",
"enum": [
"ByCreateTimeAsc",
"ByCreateTimeDesc",
"ByActiveTimeAsc",
"ByActiveTimeDesc"
]
},
"description": "Sort order for the chat list"
}
],
"responses": {
"200": {
"description": "Chat list response"
}
}
}
},
"/im/v1/chats/{chat_id}": {
"get": {
"summary": "Get details for one chat",
"parameters": [
{
"name": "chat_id",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Feishu chat identifier"
}
],
"responses": {
"200": {
"description": "Chat detail response"
}
}
}
},
"/im/v1/chats/{chat_id}/members": {
"get": {
"summary": "List members of a chat",
"parameters": [
{
"name": "chat_id",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Feishu chat identifier"
},
{
"name": "member_id_type",
"in": "query",
"required": false,
"schema": {
"type": "string",
"enum": [
"open_id",
"union_id",
"user_id"
]
},
"description": "Identifier type for returned members"
},
{
"name": "page_size",
"in": "query",
"required": false,
"schema": {
"type": "integer",
"minimum": 1,
"maximum": 100
},
"description": "Number of members to return"
},
{
"name": "page_token",
"in": "query",
"required": false,
"schema": {
"type": "string"
},
"description": "Pagination token from a previous response"
}
],
"responses": {
"200": {
"description": "Chat member list response"
}
}
}
},
"/im/v1/messages": {
"get": {
"summary": "List historical messages for a container",
"parameters": [
{
"name": "container_id_type",
"in": "query",
"required": true,
"schema": {
"type": "string",
"enum": [
"chat"
]
},
"description": "Container type used for the lookup"
},
{
"name": "container_id",
"in": "query",
"required": true,
"schema": {
"type": "string"
},
"description": "Chat identifier whose history should be returned"
},
{
"name": "sort_type",
"in": "query",
"required": false,
"schema": {
"type": "string",
"enum": [
"ByCreateTimeAsc",
"ByCreateTimeDesc"
]
},
"description": "Sort order for the message history"
},
{
"name": "page_size",
"in": "query",
"required": false,
"schema": {
"type": "integer",
"minimum": 1,
"maximum": 50
},
"description": "Number of messages to return"
},
{
"name": "page_token",
"in": "query",
"required": false,
"schema": {
"type": "string"
},
"description": "Pagination token from a previous response"
},
{
"name": "start_time",
"in": "query",
"required": false,
"schema": {
"type": "string"
},
"description": "Inclusive start time filter, typically epoch milliseconds as a string"
},
{
"name": "end_time",
"in": "query",
"required": false,
"schema": {
"type": "string"
},
"description": "Inclusive end time filter, typically epoch milliseconds as a string"
}
],
"responses": {
"200": {
"description": "Message history response"
}
}
},
"post": {
"summary": "Send a message to a user, chat, or thread target",
"parameters": [
{
"name": "receive_id_type",
"in": "query",
"required": true,
"schema": {
"type": "string",
"enum": [
"open_id",
"user_id",
"union_id",
"chat_id",
"email"
]
},
"description": "Identifier type for the receive_id field"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CreateMessageRequest"
}
}
}
},
"responses": {
"200": {
"description": "Send message response"
}
}
}
},
"/im/v1/messages/{message_id}": {
"get": {
"summary": "Get one message by ID",
"parameters": [
{
"name": "message_id",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Feishu message identifier"
}
],
"responses": {
"200": {
"description": "Message detail response"
}
}
}
},
"/im/v1/messages/{message_id}/reply": {
"post": {
"summary": "Reply to an existing message",
"parameters": [
{
"name": "message_id",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Message identifier to reply to"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ReplyMessageRequest"
}
}
}
},
"responses": {
"200": {
"description": "Reply message response"
}
}
}
},
"/im/v1/images": {
"post": {
"summary": "Upload an image and receive an image_key",
"requestBody": {
"required": true,
"content": {
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/UploadImageRequest"
}
}
}
},
"responses": {
"200": {
"description": "Image upload response"
}
}
}
},
"/im/v1/files": {
"post": {
"summary": "Upload a file and receive a file_key",
"requestBody": {
"required": true,
"content": {
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/UploadFileRequest"
}
}
}
},
"responses": {
"200": {
"description": "File upload response"
}
}
}
},
"/contact/v3/users/{user_id}": {
"get": {
"summary": "Get one user profile",
"parameters": [
{
"name": "user_id",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "User identifier"
},
{
"name": "user_id_type",
"in": "query",
"required": false,
"schema": {
"type": "string",
"enum": [
"open_id",
"union_id",
"user_id"
]
},
"description": "Identifier type used for the path parameter"
},
{
"name": "department_id_type",
"in": "query",
"required": false,
"schema": {
"type": "string",
"enum": [
"department_id",
"open_department_id"
]
},
"description": "Preferred department ID type in the response"
}
],
"responses": {
"200": {
"description": "User profile response"
}
}
}
},
"/contact/v3/users/batch_get_id": {
"post": {
"summary": "Resolve user IDs from email or mobile values",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/BatchGetUserIdRequest"
}
}
}
},
"responses": {
"200": {
"description": "Batch user ID lookup response"
}
}
}
}
},
"components": {
"securitySchemes": {
"FeishuBearerAuth": {
"type": "http",
"scheme": "bearer",
"bearerFormat": "tenant_access_token"
}
},
"schemas": {
"CreateMessageRequest": {
"type": "object",
"required": [
"receive_id",
"msg_type",
"content"
],
"properties": {
"receive_id": {
"type": "string",
"description": "Target identifier whose type is defined by receive_id_type"
},
"msg_type": {
"type": "string",
"enum": [
"text",
"post",
"image",
"interactive",
"share_chat",
"share_user",
"audio",
"media",
"file",
"sticker"
],
"description": "Message content type"
},
"content": {
"type": "string",
"description": "Stringified JSON payload expected by Feishu, for example {\"text\":\"hello\"}"
},
"uuid": {
"type": "string",
"description": "Optional client-generated idempotency token"
}
},
"additionalProperties": false
},
"ReplyMessageRequest": {
"type": "object",
"required": [
"content"
],
"properties": {
"content": {
"type": "string",
"description": "Stringified JSON payload expected by Feishu, for example {\"text\":\"reply\"}"
},
"msg_type": {
"type": "string",
"enum": [
"text",
"post",
"image",
"interactive",
"share_chat",
"share_user",
"audio",
"media",
"file",
"sticker"
],
"description": "Message content type. Defaults vary by API behavior; set it explicitly."
},
"uuid": {
"type": "string",
"description": "Optional client-generated idempotency token"
}
},
"additionalProperties": false
},
"UploadImageRequest": {
"type": "object",
"required": [
"image_type",
"image"
],
"properties": {
"image_type": {
"type": "string",
"enum": [
"message"
],
"description": "Image upload purpose. Use message for IM sends."
},
"image": {
"type": "string",
"format": "binary",
"description": "Local image file path to upload"
}
},
"additionalProperties": false
},
"UploadFileRequest": {
"type": "object",
"required": [
"file_type",
"file_name",
"file"
],
"properties": {
"file_type": {
"type": "string",
"description": "File upload type. Use stream for general file uploads."
},
"file_name": {
"type": "string",
"description": "Original filename shown in Feishu"
},
"file": {
"type": "string",
"format": "binary",
"description": "Local file path to upload"
},
"duration": {
"type": "integer",
"description": "Optional duration in milliseconds for audio or video uploads"
}
},
"additionalProperties": false
},
"BatchGetUserIdRequest": {
"type": "object",
"properties": {
"emails": {
"type": "array",
"items": {
"type": "string",
"format": "email"
},
"description": "Email addresses to resolve"
},
"mobiles": {
"type": "array",
"items": {
"type": "string"
},
"description": "Mobile numbers to resolve"
},
"include_resigned": {
"type": "boolean",
"description": "Whether to include resigned users in the lookup"
}
},
"additionalProperties": false
}
}
}
}
FILE:references/usage-patterns.md
# Feishu / Lark IM Skill - Usage Patterns
## Link Setup
```bash
command -v feishu-openapi-cli
uxc link feishu-openapi-cli https://open.feishu.cn/open-apis \
--schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/feishu-openapi-skill/references/feishu-im.openapi.json
feishu-openapi-cli -h
```
For international Lark tenants, use the same schema against `https://open.larksuite.com/open-apis`.
## Token Bootstrap
Preferred path: let `uxc` manage tenant-token bootstrap and refresh from app credentials.
```bash
uxc auth credential set feishu-tenant \
--auth-type bearer \
--field app_id=env:FEISHU_APP_ID \
--field app_secret=env:FEISHU_APP_SECRET
uxc auth bootstrap set feishu-tenant \
--token-endpoint https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal \
--header 'Content-Type=application/json; charset=utf-8' \
--request-json '{"app_id":"{{field:app_id}}","app_secret":"{{field:app_secret}}"}' \
--access-token-pointer /tenant_access_token \
--expires-in-pointer /expire \
--success-code-pointer /code \
--success-code-value 0
uxc auth bootstrap info feishu-tenant
```
For long-connection subscribe, keep this same credential because the transport needs the stored `app_id` and `app_secret` fields to open a fresh temporary WebSocket URL.
Manual fallback:
For Feishu tenants:
```bash
curl -sS https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal \
-H 'Content-Type: application/json; charset=utf-8' \
-d '{"app_id":"cli_xxx","app_secret":"xxxx"}'
```
For Lark tenants, call the same path on the Lark host:
```bash
curl -sS https://open.larksuite.com/open-apis/auth/v3/tenant_access_token/internal \
-H 'Content-Type: application/json; charset=utf-8' \
-d '{"app_id":"cli_xxx","app_secret":"xxxx"}'
```
Store the resulting `tenant_access_token` in an environment variable before binding it into `uxc auth` if you are using the manual fallback.
## Auth Setup
```bash
uxc auth credential set feishu-tenant \
--auth-type bearer \
--secret-env FEISHU_TENANT_ACCESS_TOKEN
uxc auth binding add \
--id feishu-tenant \
--host open.feishu.cn \
--path-prefix /open-apis \
--scheme https \
--credential feishu-tenant \
--priority 100
```
## Read Examples
```bash
# List chats visible to the app
feishu-openapi-cli get:/im/v1/chats page_size=20
# Inspect one chat
feishu-openapi-cli get:/im/v1/chats/{chat_id} chat_id=oc_xxx
# List chat members
feishu-openapi-cli get:/im/v1/chats/{chat_id}/members chat_id=oc_xxx page_size=50
# Read recent messages from one chat
feishu-openapi-cli get:/im/v1/messages container_id_type=chat container_id=oc_xxx page_size=20
# Read one message by id
feishu-openapi-cli get:/im/v1/messages/{message_id} message_id=om_xxx
# Look up a user profile
feishu-openapi-cli get:/contact/v3/users/{user_id} user_id=ou_xxx user_id_type=open_id
```
## Write Examples (Confirm Intent First)
```bash
# Upload an image and capture the returned image_key
feishu-openapi-cli post:/im/v1/images image_type=message image=/tmp/example.png
# Upload a file and capture the returned file_key
feishu-openapi-cli post:/im/v1/files file_type=stream file_name=report.txt file=/tmp/report.txt
# Send a text message to a chat
feishu-openapi-cli post:/im/v1/messages receive_id_type=chat_id '{"receive_id":"oc_xxx","msg_type":"text","content":"{\"text\":\"Hello from UXC\"}"}'
# Send an image message using a previously uploaded image_key
feishu-openapi-cli post:/im/v1/messages receive_id_type=chat_id '{"receive_id":"oc_xxx","msg_type":"image","content":"{\"image_key\":\"img_xxx\"}"}'
# Send a file message using a previously uploaded file_key
feishu-openapi-cli post:/im/v1/messages receive_id_type=chat_id '{"receive_id":"oc_xxx","msg_type":"file","content":"{\"file_key\":\"file_xxx\"}"}'
# Send a text message to a user by open_id
feishu-openapi-cli post:/im/v1/messages receive_id_type=open_id '{"receive_id":"ou_xxx","msg_type":"text","content":"{\"text\":\"Hello from UXC\"}"}'
# Reply to a message
feishu-openapi-cli post:/im/v1/messages/{message_id}/reply '{"message_id":"om_xxx","content":"{\"text\":\"Reply from UXC\"}","msg_type":"text"}'
```
## Long-Connection Subscribe
Use `uxc subscribe` directly for inbound Feishu/Lark message intake:
```bash
uxc subscribe start https://open.feishu.cn/open-apis \
--transport feishu-long-connection \
--auth feishu-tenant \
--sink file:$HOME/.uxc/subscriptions/feishu.ndjson
```
What to expect:
- the sink starts with an `open` event containing the temporary Feishu WebSocket URL
- inbound bot-visible messages arrive as `data` events
- real Feishu IM events use `data.header.event_type`, for example:
- `im.message.receive_v1`
Important notes:
- this transport is provider-aware; it is not a generic raw WebSocket JSON stream
- the runtime handles temporary URL bootstrap, protobuf binary frames, event acknowledgements, and ping control frames automatically
- use a credential that still has `app_id` and `app_secret` fields, even if request/response calls are already using bootstrap-managed bearer auth
## Fallback Equivalence
- `feishu-openapi-cli <operation> ...` is equivalent to
`uxc https://open.feishu.cn/open-apis --schema-url <feishu_openapi_schema> <operation> ...`.
FILE:scripts/validate.sh
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "BASH_SOURCE[0]")/../../.." && pwd)"
SKILL_DIR="ROOT_DIR/skills/feishu-openapi-skill"
SKILL_FILE="SKILL_DIR/SKILL.md"
OPENAI_FILE="SKILL_DIR/agents/openai.yaml"
USAGE_FILE="SKILL_DIR/references/usage-patterns.md"
SCHEMA_FILE="SKILL_DIR/references/feishu-im.openapi.json"
fail() {
printf '[validate] error: %s\n' "$*" >&2
exit 1
}
need_cmd() {
command -v "$1" >/dev/null 2>&1 || fail "required command not found: $1"
}
need_cmd rg
need_cmd jq
for file in "SKILL_FILE" "OPENAI_FILE" "USAGE_FILE" "SCHEMA_FILE"; do
[[ -f "file" ]] || fail "missing required file: file"
done
jq -e '.openapi and .paths' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'invalid OpenAPI schema JSON or missing .openapi/.paths'
jq -e '.paths["/im/v1/chats"]' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'OpenAPI schema missing /im/v1/chats path'
jq -e '.paths["/im/v1/images"]' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'OpenAPI schema missing /im/v1/images path'
jq -e '.paths["/im/v1/files"]' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'OpenAPI schema missing /im/v1/files path'
rg -q '^name:\s*feishu-openapi-skill\s*$' "SKILL_FILE" || fail 'invalid skill name'
rg -q '^description:\s*.+' "SKILL_FILE" || fail 'missing description'
rg -q 'command -v feishu-openapi-cli' "SKILL_FILE" || fail 'missing link-first command check'
rg -q 'uxc link feishu-openapi-cli https://open.feishu.cn/open-apis --schema-url ' "SKILL_FILE" || fail 'missing fixed link create command with schema-url'
rg -q 'feishu-openapi-cli -h' "SKILL_FILE" || fail 'missing help-first host discovery example'
rg -q 'feishu-openapi-cli get:/im/v1/chats -h' "SKILL_FILE" || fail 'missing operation-level help example'
rg -q 'feishu-openapi-cli post:/im/v1/images -h' "SKILL_FILE" || fail 'missing image upload help example'
rg -q 'feishu-openapi-cli post:/im/v1/files -h' "SKILL_FILE" || fail 'missing file upload help example'
rg -q -- '--auth-type bearer' "SKILL_FILE" || fail 'missing bearer auth setup'
rg -q 'tenant_access_token' "SKILL_FILE" || fail 'missing tenant access token guidance'
rg -q 'uxc auth binding match https://open.feishu.cn/open-apis' "SKILL_FILE" || fail 'missing binding match check'
rg -q 'receive_id_type' "SKILL_FILE" || fail 'missing receive_id_type guardrail'
rg -q 'content` field is a JSON-encoded string' "SKILL_FILE" || fail 'missing content-string guardrail'
rg -q 'multipart/form-data' "SKILL_FILE" || fail 'missing multipart upload guardrail'
rg -q 'positional JSON' "SKILL_FILE" || fail 'missing positional JSON guidance'
if rg -q -- "--args\\s+'\\{" "SKILL_FILE" "USAGE_FILE"; then
fail 'found banned legacy JSON argument pattern'
fi
rg -q '^\s*display_name:\s*"Feishu / Lark IM"\s*$' "OPENAI_FILE" || fail 'missing display_name'
rg -q '^\s*short_description:\s*".+"\s*$' "OPENAI_FILE" || fail 'missing short_description'
rg -q '^\s*default_prompt:\s*".*\$feishu-openapi-skill.*"\s*$' "OPENAI_FILE" || fail 'default_prompt must mention $feishu-openapi-skill'
echo "skills/feishu-openapi-skill validation passed"
Operate Telegram Bot API through UXC with a curated OpenAPI schema, bot-token path auth, polling-based reads, and webhook management guardrails.
---
name: telegram-openapi-skill
description: Operate Telegram Bot API through UXC with a curated OpenAPI schema, bot-token path auth, polling-based reads, and webhook management guardrails.
---
# Telegram Bot API Skill
Use this skill to run Telegram Bot API operations through `uxc` + OpenAPI.
Reuse the `uxc` skill for shared execution, auth, and error-handling guidance.
## Prerequisites
- `uxc` is installed and available in `PATH`.
- Network access to `https://api.telegram.org`.
- Access to the curated OpenAPI schema URL:
- `https://raw.githubusercontent.com/holon-run/uxc/main/skills/telegram-openapi-skill/references/telegram-bot.openapi.json`
- A Telegram bot token from BotFather.
## Scope
This skill covers a lean bot core surface:
- bot identity and chat lookup
- text sends
- media sends by `file_id`, HTTP URL, or local multipart upload
- polling via `getUpdates`
- webhook setup/status/delete operations
This skill does **not** cover:
- multipart media groups with `attach://` file arrays
- generic webhook ingestion/runtime hosting
- the full Telegram Bot API surface
## Authentication
Telegram Bot API requires the bot token in the request path: `https://api.telegram.org/bot<TOKEN>/METHOD_NAME`.
Configure the credential with a request path prefix template:
```bash
uxc auth credential set telegram-bot \
--auth-type api_key \
--secret-env TELEGRAM_BOT_TOKEN \
--path-prefix-template "/bot{{secret}}"
uxc auth binding add \
--id telegram-bot \
--host api.telegram.org \
--scheme https \
--credential telegram-bot \
--priority 100
```
Validate the local mapping when auth looks wrong:
```bash
uxc auth binding match https://api.telegram.org/getMe
```
## Core Workflow
1. Use the fixed link command by default:
- `command -v telegram-openapi-cli`
- If missing, create it:
`uxc link telegram-openapi-cli https://api.telegram.org --schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/telegram-openapi-skill/references/telegram-bot.openapi.json`
- `telegram-openapi-cli -h`
2. Inspect operation schema first:
- `telegram-openapi-cli get:/getMe -h`
- `telegram-openapi-cli post:/sendMessage -h`
- `telegram-openapi-cli post:/sendPhoto -h`
- `telegram-openapi-cli post:/sendDocument -h`
- `telegram-openapi-cli post:/getUpdates -h`
3. Prefer read/setup validation before writes:
- `telegram-openapi-cli get:/getMe`
- `telegram-openapi-cli get:/getWebhookInfo`
- `telegram-openapi-cli get:/getChat chat_id=@channel_or_chat_id`
4. Execute operations with key/value or positional JSON:
- key/value:
`telegram-openapi-cli post:/sendMessage chat_id=CHAT_ID text="Hello from uxc"`
- multipart upload:
`telegram-openapi-cli post:/sendPhoto chat_id=CHAT_ID photo=/tmp/photo.jpg caption="Uploaded by uxc"`
- positional JSON:
`telegram-openapi-cli post:/sendMessage '{"chat_id":"CHAT_ID","text":"Hello from uxc"}'`
- daemon-backed polling subscribe:
`uxc subscribe start https://api.telegram.org post:/getUpdates '{"timeout":5,"allowed_updates":["message","callback_query"]}' --mode poll --poll-config '{"interval_secs":2,"extract_items_pointer":"/result","request_cursor_arg":"offset","cursor_from_item_pointer":"/update_id","cursor_transform":"increment","checkpoint_strategy":{"type":"item_key","item_key_pointer":"/update_id"}}' --sink file:/tmp/telegram-updates.ndjson`
## Runtime Validation
The following Telegram polling flow has been validated against the real Bot API through `uxc`:
- `get:/getMe`
- `get:/getWebhookInfo`
- daemon-backed `uxc subscribe --mode poll` on `post:/getUpdates`
- item-derived offset progression from `update_id + 1`
- dedupe/checkpoint behavior for repeated polls
Observed runtime behavior:
- `data` events are emitted for real Telegram updates
- `poll` events record fetched/emitted/skipped counts
- `checkpoint` events are emitted after new updates are seen
- repeated polls skip already-consumed updates after checkpoint advancement
## Operation Groups
### Read / Lookup
- `get:/getMe`
- `get:/getChat`
- `get:/getChatMember`
- `get:/getWebhookInfo`
### Messaging
- `post:/sendMessage`
- `post:/sendPhoto`
- `post:/sendDocument`
- `post:/sendMediaGroup`
### Update Delivery
- `post:/getUpdates`
- `post:/setWebhook`
- `post:/deleteWebhook`
## Guardrails
- Keep automation on the JSON output envelope; do not use `--text`.
- Parse stable fields first: `ok`, `kind`, `protocol`, `data`, `error`.
- `getUpdates` and webhook delivery are mutually exclusive:
- if a webhook is configured, call `post:/deleteWebhook` before polling with `post:/getUpdates`
- if polling is active, do not treat webhook operations as background subscription support
- Telegram allows only one active `getUpdates` consumer per bot token:
- if another bot process or script is polling at the same time, Telegram returns HTTP 409
- stop the other consumer before relying on daemon-backed polling subscribe
- For daemon-backed polling subscribe, prefer item-derived offset progression:
- `extract_items_pointer` should be `/result`
- `request_cursor_arg` should be `offset`
- `cursor_from_item_pointer` should be `/update_id`
- `cursor_transform` should be `increment`
- `checkpoint_strategy.type` should usually be `item_key` with `item_key_pointer=/update_id`
- `uxc auth binding match` should be checked against a concrete Telegram method URL such as `https://api.telegram.org/getMe`, because auth is applied through a path-prefix template that expands to `/bot<TOKEN>/...`.
- `sendPhoto`, `sendDocument`, and `sendMediaGroup` in this skill accept existing `file_id` values or HTTP URLs only; they do not upload new local files.
- `sendPhoto` and `sendDocument` also support `multipart/form-data` local file uploads. File fields must be local path strings.
- `sendMediaGroup` still stays JSON-only in this skill because current multipart v1 does not model the `media` array plus `attach://` file set cleanly.
- `setWebhook` supports multipart certificate upload for self-signed certs through the `certificate` file field.
- Treat `post:/sendMessage`, all `send*` operations, and webhook-changing operations as write/high-risk actions; require explicit user confirmation before execution.
- `telegram-openapi-cli <operation> ...` is equivalent to `uxc https://api.telegram.org --schema-url <telegram_openapi_schema> <operation> ...`.
## References
- Usage patterns: `references/usage-patterns.md`
- Curated OpenAPI schema: `references/telegram-bot.openapi.json`
- Telegram Bot API docs: https://core.telegram.org/bots/api
- Local Bot API server: https://github.com/tdlib/telegram-bot-api
FILE:agents/openai.yaml
interface:
display_name: "Telegram Bot API"
short_description: "Operate Telegram Bot API via UXC + curated OpenAPI schema"
default_prompt: "Use $telegram-openapi-skill to discover and execute Telegram Bot API operations through UXC with bot-token path auth and polling/webhook guardrails."
FILE:references/telegram-bot.openapi.json
{
"openapi": "3.0.3",
"info": {
"title": "Telegram Bot API (Curated Lean Core)",
"version": "1.0.0"
},
"servers": [
{
"url": "https://api.telegram.org"
}
],
"paths": {
"/getMe": {
"get": {
"summary": "Get basic bot identity information",
"responses": {
"200": {
"description": "Bot identity response"
}
}
}
},
"/getChat": {
"get": {
"summary": "Get information about a chat the bot can access",
"parameters": [
{
"name": "chat_id",
"in": "query",
"required": true,
"schema": {
"type": "string"
},
"description": "Unique identifier for the target chat or username of the target supergroup/channel"
}
],
"responses": {
"200": {
"description": "Chat info response"
}
}
}
},
"/getChatMember": {
"get": {
"summary": "Get information about a member of a chat",
"parameters": [
{
"name": "chat_id",
"in": "query",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "user_id",
"in": "query",
"required": true,
"schema": {
"type": "integer",
"format": "int64"
}
}
],
"responses": {
"200": {
"description": "Chat member response"
}
}
}
},
"/getWebhookInfo": {
"get": {
"summary": "Get current webhook status",
"responses": {
"200": {
"description": "Webhook info response"
}
}
}
},
"/sendMessage": {
"post": {
"summary": "Send a text message",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SendMessageRequest"
}
}
}
},
"responses": {
"200": {
"description": "Sent message response"
}
}
}
},
"/sendPhoto": {
"post": {
"summary": "Send a photo by file_id, HTTP URL, or local multipart upload",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SendPhotoRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/SendPhotoMultipartRequest"
}
}
}
},
"responses": {
"200": {
"description": "Sent photo response"
}
}
}
},
"/sendDocument": {
"post": {
"summary": "Send a document by file_id, HTTP URL, or local multipart upload",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SendDocumentRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/SendDocumentMultipartRequest"
}
}
}
},
"responses": {
"200": {
"description": "Sent document response"
}
}
}
},
"/sendMediaGroup": {
"post": {
"summary": "Send a group of photos or documents by file_id or HTTP URL",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SendMediaGroupRequest"
}
}
}
},
"responses": {
"200": {
"description": "Sent media group response"
}
}
}
},
"/getUpdates": {
"post": {
"summary": "Poll for incoming updates",
"requestBody": {
"required": false,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/GetUpdatesRequest"
}
}
}
},
"responses": {
"200": {
"description": "Updates response"
}
}
}
},
"/setWebhook": {
"post": {
"summary": "Configure webhook delivery, optionally with multipart certificate upload",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SetWebhookRequest"
}
},
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/SetWebhookMultipartRequest"
}
}
}
},
"responses": {
"200": {
"description": "Webhook set response"
}
}
}
},
"/deleteWebhook": {
"post": {
"summary": "Delete webhook configuration",
"requestBody": {
"required": false,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/DeleteWebhookRequest"
}
}
}
},
"responses": {
"200": {
"description": "Webhook delete response"
}
}
}
}
},
"components": {
"schemas": {
"ChatId": {
"oneOf": [
{
"type": "string"
},
{
"type": "integer",
"format": "int64"
}
]
},
"ReplyMarkup": {
"type": "object",
"additionalProperties": true,
"description": "Telegram reply markup object passed as JSON"
},
"SendMessageRequest": {
"type": "object",
"required": [
"chat_id",
"text"
],
"properties": {
"chat_id": {
"$ref": "#/components/schemas/ChatId"
},
"text": {
"type": "string"
},
"parse_mode": {
"type": "string"
},
"disable_notification": {
"type": "boolean"
},
"protect_content": {
"type": "boolean"
},
"reply_markup": {
"$ref": "#/components/schemas/ReplyMarkup"
}
},
"additionalProperties": true
},
"SendPhotoRequest": {
"type": "object",
"required": [
"chat_id",
"photo"
],
"properties": {
"chat_id": {
"$ref": "#/components/schemas/ChatId"
},
"photo": {
"type": "string",
"description": "Existing file_id or HTTP URL only in this curated schema"
},
"caption": {
"type": "string"
},
"parse_mode": {
"type": "string"
},
"disable_notification": {
"type": "boolean"
},
"protect_content": {
"type": "boolean"
},
"reply_markup": {
"$ref": "#/components/schemas/ReplyMarkup"
}
},
"additionalProperties": true
},
"SendPhotoMultipartRequest": {
"type": "object",
"required": [
"chat_id",
"photo"
],
"properties": {
"chat_id": {
"$ref": "#/components/schemas/ChatId"
},
"photo": {
"type": "string",
"format": "binary",
"description": "Local file path to upload as the photo body"
},
"caption": {
"type": "string"
},
"parse_mode": {
"type": "string"
},
"disable_notification": {
"type": "boolean"
},
"protect_content": {
"type": "boolean"
}
},
"additionalProperties": false
},
"SendDocumentRequest": {
"type": "object",
"required": [
"chat_id",
"document"
],
"properties": {
"chat_id": {
"$ref": "#/components/schemas/ChatId"
},
"document": {
"type": "string",
"description": "Existing file_id or HTTP URL only in this curated schema"
},
"caption": {
"type": "string"
},
"parse_mode": {
"type": "string"
},
"disable_notification": {
"type": "boolean"
},
"protect_content": {
"type": "boolean"
},
"reply_markup": {
"$ref": "#/components/schemas/ReplyMarkup"
}
},
"additionalProperties": true
},
"SendDocumentMultipartRequest": {
"type": "object",
"required": [
"chat_id",
"document"
],
"properties": {
"chat_id": {
"$ref": "#/components/schemas/ChatId"
},
"document": {
"type": "string",
"format": "binary",
"description": "Local file path to upload as the document body"
},
"caption": {
"type": "string"
},
"parse_mode": {
"type": "string"
},
"disable_notification": {
"type": "boolean"
},
"protect_content": {
"type": "boolean"
}
},
"additionalProperties": false
},
"InputMediaItem": {
"type": "object",
"required": [
"type",
"media"
],
"properties": {
"type": {
"type": "string",
"enum": [
"photo",
"document"
]
},
"media": {
"type": "string",
"description": "Existing file_id or HTTP URL only in this curated schema"
},
"caption": {
"type": "string"
},
"parse_mode": {
"type": "string"
}
},
"additionalProperties": true
},
"SendMediaGroupRequest": {
"type": "object",
"required": [
"chat_id",
"media"
],
"properties": {
"chat_id": {
"$ref": "#/components/schemas/ChatId"
},
"media": {
"type": "array",
"minItems": 2,
"items": {
"$ref": "#/components/schemas/InputMediaItem"
}
},
"disable_notification": {
"type": "boolean"
},
"protect_content": {
"type": "boolean"
},
"reply_to_message_id": {
"type": "integer",
"format": "int64"
}
},
"additionalProperties": true
},
"GetUpdatesRequest": {
"type": "object",
"properties": {
"offset": {
"type": "integer",
"format": "int64"
},
"limit": {
"type": "integer"
},
"timeout": {
"type": "integer"
},
"allowed_updates": {
"type": "array",
"items": {
"type": "string"
}
}
},
"additionalProperties": true
},
"SetWebhookRequest": {
"type": "object",
"required": [
"url"
],
"properties": {
"url": {
"type": "string"
},
"ip_address": {
"type": "string"
},
"max_connections": {
"type": "integer"
},
"allowed_updates": {
"type": "array",
"items": {
"type": "string"
}
},
"drop_pending_updates": {
"type": "boolean"
},
"secret_token": {
"type": "string"
}
},
"additionalProperties": true
},
"SetWebhookMultipartRequest": {
"type": "object",
"required": [
"url"
],
"properties": {
"url": {
"type": "string"
},
"certificate": {
"type": "string",
"format": "binary",
"description": "Local PEM certificate file path for self-signed webhook setups"
},
"ip_address": {
"type": "string"
},
"max_connections": {
"type": "integer"
},
"drop_pending_updates": {
"type": "boolean"
},
"secret_token": {
"type": "string"
}
},
"additionalProperties": false
},
"DeleteWebhookRequest": {
"type": "object",
"properties": {
"drop_pending_updates": {
"type": "boolean"
}
},
"additionalProperties": true
}
}
}
}
FILE:references/usage-patterns.md
# Telegram Bot API Skill - Usage Patterns
## Link Setup
```bash
command -v telegram-openapi-cli
uxc link telegram-openapi-cli https://api.telegram.org \
--schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/telegram-openapi-skill/references/telegram-bot.openapi.json
telegram-openapi-cli -h
```
## Auth Setup
```bash
uxc auth credential set telegram-bot \
--auth-type api_key \
--secret-env TELEGRAM_BOT_TOKEN \
--path-prefix-template "/bot{{secret}}"
uxc auth binding add \
--id telegram-bot \
--host api.telegram.org \
--scheme https \
--credential telegram-bot \
--priority 100
uxc auth binding match https://api.telegram.org/getMe
```
## Read Examples
```bash
# Confirm the bot identity
telegram-openapi-cli get:/getMe
# Inspect a chat the bot can access
telegram-openapi-cli get:/getChat chat_id=@my_channel
# Check webhook state before deciding between webhook and polling
telegram-openapi-cli get:/getWebhookInfo
```
## Polling Example
```bash
# Remove webhook first if one is configured
telegram-openapi-cli post:/deleteWebhook '{"drop_pending_updates":false}'
# Poll for updates with long-poll timeout
telegram-openapi-cli post:/getUpdates '{"timeout":30,"allowed_updates":["message","callback_query"]}'
# Run background polling through uxc subscribe with offset derived from update_id + 1
# Only one getUpdates consumer can be active for the bot token at a time.
uxc subscribe start https://api.telegram.org post:/getUpdates \
'{"timeout":5,"allowed_updates":["message","callback_query"]}' \
--mode poll \
--poll-config '{"interval_secs":2,"extract_items_pointer":"/result","request_cursor_arg":"offset","cursor_from_item_pointer":"/update_id","cursor_transform":"increment","checkpoint_strategy":{"type":"item_key","item_key_pointer":"/update_id"}}' \
--sink file:/tmp/telegram-updates.ndjson
```
## Write Examples (Confirm Intent First)
```bash
# Send a text message
telegram-openapi-cli post:/sendMessage '{"chat_id":"CHAT_ID","text":"Hello from UXC"}'
# Send a photo by existing file_id or HTTP URL
telegram-openapi-cli post:/sendPhoto '{"chat_id":"CHAT_ID","photo":"https://example.com/photo.jpg","caption":"From UXC"}'
# Send a photo by local multipart upload
telegram-openapi-cli post:/sendPhoto chat_id=CHAT_ID photo=/tmp/photo.jpg caption="Uploaded by UXC"
# Send a document by local multipart upload
telegram-openapi-cli post:/sendDocument chat_id=CHAT_ID document=/tmp/report.pdf caption="Report"
# Configure a webhook with a self-signed certificate file
telegram-openapi-cli post:/setWebhook url=https://example.com/telegram-webhook certificate=/tmp/public.pem secret_token=secret123
```
## Fallback Equivalence
- `telegram-openapi-cli <operation> ...` is equivalent to
`uxc https://api.telegram.org --schema-url <telegram_openapi_schema> <operation> ...`.
FILE:scripts/validate.sh
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "BASH_SOURCE[0]")/../../.." && pwd)"
SKILL_DIR="ROOT_DIR/skills/telegram-openapi-skill"
SKILL_FILE="SKILL_DIR/SKILL.md"
OPENAI_FILE="SKILL_DIR/agents/openai.yaml"
USAGE_FILE="SKILL_DIR/references/usage-patterns.md"
SCHEMA_FILE="SKILL_DIR/references/telegram-bot.openapi.json"
fail() {
printf '[validate] error: %s\n' "$*" >&2
exit 1
}
need_cmd() {
command -v "$1" >/dev/null 2>&1 || fail "required command not found: $1"
}
need_cmd rg
for file in "SKILL_FILE" "OPENAI_FILE" "USAGE_FILE" "SCHEMA_FILE"; do
[[ -f "file" ]] || fail "missing required file: file"
done
rg -q '^name:\s*telegram-openapi-skill\s*$' "SKILL_FILE" || fail 'invalid skill name'
rg -q '^description:\s*.+' "SKILL_FILE" || fail 'missing description'
rg -q 'command -v telegram-openapi-cli' "SKILL_FILE" || fail 'missing link-first command check'
rg -q 'uxc link telegram-openapi-cli https://api.telegram.org --schema-url ' "SKILL_FILE" || fail 'missing fixed link create command with schema-url'
rg -q 'telegram-openapi-cli -h' "SKILL_FILE" || fail 'missing help-first host discovery example'
rg -q 'telegram-openapi-cli get:/getMe -h' "SKILL_FILE" || fail 'missing operation-level help example'
rg -q 'telegram-openapi-cli post:/sendPhoto -h' "SKILL_FILE" || fail 'missing multipart photo help example'
rg -q 'telegram-openapi-cli post:/sendDocument -h' "SKILL_FILE" || fail 'missing multipart document help example'
rg -q -- '--path-prefix-template "/bot\{\{secret\}\}"' "SKILL_FILE" || fail 'missing Telegram path auth setup'
rg -q 'uxc auth binding match https://api.telegram.org' "SKILL_FILE" || fail 'missing binding match check'
rg -q 'multipart/form-data' "SKILL_FILE" || fail 'missing multipart guidance'
rg -q 'positional JSON' "SKILL_FILE" || fail 'missing positional JSON guidance'
if rg -q -- "--args\\s+'\\{" "SKILL_FILE" "USAGE_FILE"; then
fail 'found banned legacy JSON argument pattern'
fi
rg -q '^\s*display_name:\s*"Telegram Bot API"\s*$' "OPENAI_FILE" || fail 'missing display_name'
rg -q '^\s*short_description:\s*".+"\s*$' "OPENAI_FILE" || fail 'missing short_description'
rg -q '^\s*default_prompt:\s*".*\$telegram-openapi-skill.*"\s*$' "OPENAI_FILE" || fail 'default_prompt must mention $telegram-openapi-skill'
echo "skills/telegram-openapi-skill validation passed"