@clawhub-jolestar-21112cba96
Use when an agent needs to install or use indexbind from Node, browsers, Web Workers, or Cloudflare Workers. This skill helps choose the right package, CLI,...
--- name: indexbind version: 1.0.1 description: Use when an agent needs to install or use indexbind from Node, browsers, Web Workers, or Cloudflare Workers. This skill helps choose the right package, CLI, artifact, and entrypoint, and points to the live markdown docs for details. --- # Indexbind Use this skill when the task is about using `indexbind` from a host application or environment. ## Usage examples - "Use `indexbind` to add local search to a docs folder." - "Help me choose between `indexbind`, `indexbind/web`, and `indexbind/cloudflare`." - "Show me how to build a SQLite artifact for Node and a bundle for Workers." ## Install Install the package: ```bash npm install indexbind ``` Optional global install when the goal is using `indexbind` as a shell command from arbitrary directories: ```bash npm install -g indexbind ``` Then use either: - `npx indexbind ...` for local installs and per-project workflows - `indexbind ...` after a global install - `import ... from 'indexbind'` or `indexbind/build` for programmatic usage Platform notes: - native prebuilds exist for macOS arm64, macOS x64, and Linux x64 (glibc) - Windows usage should go through WSL Install and packaging docs: - `https://indexbind.jolestar.workers.dev/guides/getting-started.md` - `https://indexbind.jolestar.workers.dev/reference/packaging.md` ## Choose the right interface - Index a local docs folder or local knowledge-base directory from the shell: use `npx indexbind ...` - Local Node querying over a built SQLite artifact: use `indexbind` - Programmatic build, incremental cache update, inspect, or benchmark: use `indexbind/build` - Mixed local knowledge bases that need host-defined document classification, metadata, or directory weighting: normalize documents in the host first, then pass them to `indexbind/build` - A mostly-default local docs or knowledge-base directory that only needs light host policy: use `indexbind.build.js` and `indexbind.search.js` beside that directory’s `.indexbind/` - Browser or standard worker querying over a canonical bundle: use `indexbind/web` - Cloudflare Worker querying: use `indexbind/cloudflare` - Shell-driven build/update/export/inspect flows: use `npx indexbind ...` API docs: - `https://indexbind.jolestar.workers.dev/reference/api.md` - `https://indexbind.jolestar.workers.dev/reference/cli.md` ## Choose the artifact - Local directory indexing for later Node queries: build a native SQLite artifact - Local directory indexing for browser or worker delivery: build a canonical bundle - Node runtime: use a native SQLite artifact - Browser, Web Worker, Cloudflare Worker: use a canonical bundle - Repeated rebuilds over a stable corpus: use the build cache, then export fresh artifacts or bundles Concepts: - `https://indexbind.jolestar.workers.dev/concepts/runtime-model.md` - `https://indexbind.jolestar.workers.dev/concepts/canonical-bundles.md` ## Common commands Typical CLI commands: - `npx indexbind build ./docs` - `npx indexbind build-bundle ./docs` - `npx indexbind update-cache ./docs --git-diff` - `npx indexbind build [input-dir] [output-file] [--backend <hashing|model-id>]` - `npx indexbind build-bundle [input-dir] [output-dir] [--backend <hashing|model-id>]` - `npx indexbind update-cache [input-dir] [cache-file] [--git-diff] [--git-base <rev>] [--backend <hashing|model-id>]` - `npx indexbind export-artifact <output-file> [--cache-file <path>]` - `npx indexbind export-bundle <output-dir> [--cache-file <path>]` - `npx indexbind inspect <artifact-file>` - `npx indexbind search <artifact-file> <query>` - `npx indexbind benchmark <artifact-file> <queries-json>` Use `indexbind/build` instead when the host already has documents in memory or wants tighter control from code. ## Index-scoped conventions When one indexed root only needs a small amount of host-specific behavior, place convention files beside that root: ```text docs/ indexbind.build.js indexbind.search.js .indexbind/ ``` Use `indexbind.build.js` when the default directory scanner is already correct and you only need to: - skip a few files from indexing - derive `canonicalUrl` - inject metadata such as `is_default_searchable`, `source_root`, `content_kind`, or `directory_weight` - normalize `title` or `summary` Use `indexbind.search.js` when CLI or Node search should automatically apply: - a default search profile - a metadata filter - score adjustment defaults - lightweight query rewrite or alias expansion These convention files are index-scoped, not repo-global: - if you index `./docs`, the files live in `./docs/` - they affect only that indexed root - there is no repo-root fallback ## Common APIs Use these APIs when the host already has documents or wants tighter control: - `openIndex(...)` from `indexbind` - `buildFromDirectory(...)` from `indexbind/build` - `buildCanonicalBundle(...)` from `indexbind/build` - `buildCanonicalBundleFromDirectory(...)` from `indexbind/build` - `updateBuildCache(...)` from `indexbind/build` - `updateBuildCacheFromDirectory(...)` from `indexbind/build` - `exportArtifactFromBuildCache(...)` from `indexbind/build` - `exportCanonicalBundleFromBuildCache(...)` from `indexbind/build` - `inspectArtifact(...)` from `indexbind/build` - `benchmarkArtifact(...)` from `indexbind/build` - `openWebIndex(...)` from `indexbind/web` - `openWebIndex(...)` from `indexbind/cloudflare` Docs: - `https://indexbind.jolestar.workers.dev/reference/api.md` - `https://indexbind.jolestar.workers.dev/guides/adoption-examples.md` - `https://indexbind.jolestar.workers.dev/reference/cli.md` ## Cloudflare rule Inside Cloudflare Workers: - prefer `indexbind/cloudflare` - if bundle files are not directly exposed as public URLs, pass a custom `fetch` to `openWebIndex(...)` - use the host asset loader such as `ASSETS.fetch(...)` rather than monkey-patching global fetch Docs: - `https://indexbind.jolestar.workers.dev/guides/web-and-cloudflare.md` - `https://indexbind.jolestar.workers.dev/reference/api.md` ## Read in this order when unsure 1. `https://indexbind.jolestar.workers.dev/guides/getting-started.md` 2. `https://indexbind.jolestar.workers.dev/reference/api.md` 3. `https://indexbind.jolestar.workers.dev/reference/cli.md` 4. `https://indexbind.jolestar.workers.dev/guides/web-and-cloudflare.md` FILE:agents/openai.yaml interface: display_name: "Indexbind" short_description: "Install and use indexbind" default_prompt: "Use $indexbind to choose the right indexbind CLI, artifact, and API path for Node, web, worker, or Cloudflare usage." policy: allow_implicit_invocation: true
Build, preview, and deploy markdown-first sites with local preview, Cloudflare bundles, and agent-readable raw markdown routes.
--- name: mdorigin description: Build, preview, and deploy markdown-first sites with local preview, Cloudflare bundles, and agent-readable raw markdown routes. --- # mdorigin Use this skill when you want to work on a markdown-first publishing site powered by `mdorigin`. ## Install Global install: ```bash npm install -g mdorigin ``` Project-local install: ```bash npm install --save-dev mdorigin ``` ## What it covers - local preview with `mdorigin dev` - directory index generation with `mdorigin build index` - search index generation with `mdorigin build search` - Cloudflare Worker bundle output with `mdorigin build cloudflare` - external binary deployment flow for Cloudflare Assets + R2 - markdown and HTML route behavior, including `Accept: text/markdown` ## Quick commands ```bash mdorigin dev --root docs/site mdorigin build index --root docs/site mdorigin build search --root docs/site mdorigin build cloudflare --root docs/site ``` External binary deploy flow: ```bash mdorigin build cloudflare --root docs/site --binary-mode external mdorigin sync cloudflare-r2 --dir dist/cloudflare --bucket <bucket-name> mdorigin init cloudflare --dir . --r2-bucket <bucket-name> ``` ## Remote docs When an agent needs details, prefer the published docs instead of duplicating everything in the skill: - HTML docs: `https://mdorigin.jolestar.workers.dev` - Raw markdown home: `https://mdorigin.jolestar.workers.dev/README.md` - Routing docs: `https://mdorigin.jolestar.workers.dev/concepts/routing.md` - Configuration docs: `https://mdorigin.jolestar.workers.dev/reference/configuration.md` - Extensions docs: `https://mdorigin.jolestar.workers.dev/guides/extensions.md` - Cloudflare docs: `https://mdorigin.jolestar.workers.dev/guides/cloudflare.md` Extensionless routes also return markdown when the client sends `Accept: text/markdown`. ## Search Use search when you need the right doc page before opening it: - Search API: `https://mdorigin.jolestar.workers.dev/api/search?q=<query>` - OpenAPI schema: `https://mdorigin.jolestar.workers.dev/api/openapi.json` Examples: ```bash curl 'https://mdorigin.jolestar.workers.dev/api/search?q=cloudflare%20deploy' curl -H 'Accept: text/markdown' 'https://mdorigin.jolestar.workers.dev/guides/getting-started' ```
Connect to X and Grok through the built-in local-mcp X adapter and one fixed UXC link. Use when the user wants to read timelines, inspect tweets, post on X,...
---
name: x-webmcp
description: Connect to X and Grok through the built-in local-mcp X adapter and one fixed UXC link. Use when the user wants to read timelines, inspect tweets, post on X, or chat with Grok from an authenticated browser profile.
---
# X WebMCP
Use this skill to operate X through the built-in `--site x` bridge preset in `@webmcp-bridge/local-mcp`.
For generic bridge setup patterns or non-X sites, switch to `$webmcp-bridge`.
## Prerequisites
- `uxc` is installed and available in `PATH`.
- `npx` is installed and available in `PATH`.
- Network access to `https://x.com`.
- On a fresh machine, or under an isolated `HOME`, install Playwright browsers first with `npx playwright install`.
- X is auth-sensitive. Expect `bootstrap_then_attach` behavior when the profile is not signed in yet.
## Core Workflow
1. Ensure the fixed X link exists:
- `command -v x-webmcp-cli`
- if missing or pointed at the wrong profile, run `skills/x-webmcp/scripts/ensure-links.sh`
2. Inspect the bridge and tool schema before calling tools:
- `x-webmcp-cli -h`
- `x-webmcp-cli timeline.home.list -h`
- `x-webmcp-cli grok.chat -h`
- `x-webmcp-cli article.publishMarkdown -h`
3. Check authentication state first when the profile is new or looks stale:
- `x-webmcp-cli bridge.session.status`
- `x-webmcp-cli auth.get`
- if the session is not ready, start bootstrap or switch to headed:
- `x-webmcp-cli bridge.session.bootstrap`
- `x-webmcp-cli bridge.session.mode.set '{"mode":"headed"}'`
- `x-webmcp-cli bridge.open`
4. Use read tools for timelines, conversations, and profiles:
- `x-webmcp-cli timeline.home.list limit=10`
- `x-webmcp-cli search.tweets.list '{"query":"playwright","mode":"latest","limit":10}'`
- `x-webmcp-cli tweet.get '{"url":"https://x.com/.../status/..."}'`
- `x-webmcp-cli tweet.conversation.get '{"id":"2033895522382319922","limit":10}'`
- `x-webmcp-cli user.get username=jack`
5. Use write tools only after reading help and confirming user intent:
- `x-webmcp-cli tweet.create '{"text":"hello from webmcp","dryRun":true}'`
- `x-webmcp-cli tweet.reply '{"id":"2033895522382319922","text":"reply text","dryRun":true}'`
- `x-webmcp-cli article.publishMarkdown '{"markdownPath":"/abs/path/post.md","dryRun":true}'`
6. Use Grok through the same authenticated X session:
- `x-webmcp-cli grok.chat '{"prompt":"Summarize this thread","timeoutMs":180000}'`
- for uploads, pass absolute local file paths in `attachmentPaths`
7. Parse JSON output only:
- success path: `.ok == true`, consume `.data`
- failure path: `.ok == false`, inspect `.error.code` and `.error.message`
## Default Target
The built-in preset uses:
```bash
--site x
```
The default profile path is:
```bash
~/.uxc/webmcp-profile/x
```
Refresh the link with:
```bash
skills/x-webmcp/scripts/ensure-links.sh
```
## Guardrails
- Keep the X profile isolated from other sites.
- X uses `bootstrap_then_attach`; do not expect page tools to work until the managed profile is authenticated.
- Prefer explicit `bridge.session.mode.set` over relaunching the command to change runtime mode.
- `grok.chat` and article publishing can take a long time. Increase `timeoutMs` instead of retrying aggressively.
- For local uploads such as `attachmentPaths`, `markdownPath`, or `coverImagePath`, always use absolute filesystem paths.
- Use `dryRun` for destructive or public write tools first when available.
- If the user closes the visible X window manually, the headed owner session ends. Run `x-webmcp-cli bridge.open` again if you still need a visible session on the same profile.
## References
- Common command patterns:
- `references/usage-patterns.md`
- Link creation helper:
- `scripts/ensure-links.sh`
FILE:agents/openai.yaml
interface:
display_name: "X WebMCP"
short_description: "Operate X and Grok through local-mcp"
default_prompt: "Use $x-webmcp to connect to X through the built-in adapter, verify auth state, and read or write X/Grok data through local-mcp."
policy:
allow_implicit_invocation: true
FILE:references/usage-patterns.md
# Usage Patterns
## Create or refresh the X link
```bash
command -v x-webmcp-cli
skills/x-webmcp/scripts/ensure-links.sh
x-webmcp-cli bridge.session.status
```
## Authenticate the managed X profile
```bash
x-webmcp-cli auth.get
x-webmcp-cli bridge.session.bootstrap
x-webmcp-cli bridge.session.mode.set '{"mode":"headed"}'
x-webmcp-cli bridge.open
```
## Read timelines and conversations
```bash
x-webmcp-cli timeline.home.list limit=10
x-webmcp-cli search.tweets.list '{"query":"playwright","mode":"latest","limit":10}'
x-webmcp-cli tweet.conversation.get '{"id":"2033895522382319922","limit":10}'
```
## Chat with Grok
```bash
x-webmcp-cli grok.chat '{"prompt":"Summarize the latest replies in this thread","timeoutMs":180000}'
```
## Dry-run a post or article publish
```bash
x-webmcp-cli tweet.create '{"text":"hello from webmcp","dryRun":true}'
x-webmcp-cli article.publishMarkdown '{"markdownPath":"/abs/path/post.md","dryRun":true}'
```
FILE:scripts/ensure-links.sh
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "BASH_SOURCE[0]")/../../.." && pwd)"
filtered_args=()
while (($#)); do
case "$1" in
--name|--site|--adapter-module|--url)
shift
if (($#)) && [[ "$1" != --* ]]; then
shift
fi
;;
--name=*|--site=*|--adapter-module=*|--url=*)
shift
;;
*)
filtered_args+=("$1")
shift
;;
esac
done
if ((#filtered_args[@] > 0)); then
exec "ROOT_DIR/skills/webmcp-bridge/scripts/ensure-links.sh" --name x --site x "filtered_args[@]"
fi
exec "ROOT_DIR/skills/webmcp-bridge/scripts/ensure-links.sh" --name x --site x
FILE:scripts/validate.sh
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "BASH_SOURCE[0]")/../../.." && pwd)"
SKILL_DIR="ROOT_DIR/skills/x-webmcp"
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
for f in \
"$SKILL_FILE" \
"$OPENAI_FILE" \
"SKILL_DIR/references/usage-patterns.md" \
"SKILL_DIR/scripts/ensure-links.sh"; do
[[ -f "$f" ]] || fail "missing required file: $f"
done
rg -q '^name:\s*x-webmcp\s*$' "$SKILL_FILE" || fail 'invalid skill name'
rg -q '^description:\s*.+' "$SKILL_FILE" || fail 'missing description'
rg -q 'command -v x-webmcp-cli' "$SKILL_FILE" || fail 'missing link-first check'
rg -q 'x-webmcp-cli -h' "$SKILL_FILE" || fail 'missing help-first usage'
rg -q 'grok.chat -h' "$SKILL_FILE" || fail 'missing Grok help example'
rg -q 'bridge.session.bootstrap' "$SKILL_FILE" || fail 'missing bootstrap guidance'
rg -q 'bridge.session.mode.set' "$SKILL_FILE" || fail 'missing headed-mode guidance'
rg -q '~/.uxc/webmcp-profile/x' "$SKILL_FILE" || fail 'missing profile convention'
if rg -q -- '(^|[[:space:]])(list|describe|call)([[:space:]]|$)|--input-json|--args .*[{]' "$SKILL_FILE" "SKILL_DIR/references"; then
fail 'found banned legacy invocation patterns'
fi
echo 'skills/x-webmcp validation passed'
Connect to Google Search and Gemini through the built-in local-mcp Google adapter and one fixed UXC link. Use when the user wants to run Google searches, cha...
---
name: google-webmcp
description: Connect to Google Search and Gemini through the built-in local-mcp Google adapter and one fixed UXC link. Use when the user wants to run Google searches, chat with Gemini, or download generated Gemini images from an authenticated browser profile.
---
# Google WebMCP
Use this skill to operate Google Search and Gemini through the built-in `--site google` bridge preset in `@webmcp-bridge/local-mcp`.
For generic bridge setup patterns or non-Google sites, switch to `$webmcp-bridge`.
## Prerequisites
- `uxc` is installed and available in `PATH`.
- `npx` is installed and available in `PATH`.
- Network access to `https://www.google.com` and `https://gemini.google.com`.
- On a fresh machine, or under an isolated `HOME`, install Playwright browsers first with `npx playwright install`.
- Gemini is auth-sensitive. Expect `bootstrap_then_attach` behavior when the profile is not signed in yet.
## Core Workflow
1. Ensure the fixed Google link exists:
- `command -v google-webmcp-cli`
- if missing or pointed at the wrong profile, run `skills/google-webmcp/scripts/ensure-links.sh`
2. Inspect the bridge and tool schema before calling tools:
- `google-webmcp-cli -h`
- `google-webmcp-cli search.web -h`
- `google-webmcp-cli gemini.chat -h`
- `google-webmcp-cli gemini.image.download -h`
3. Check authentication state first when Gemini may need sign-in:
- `google-webmcp-cli bridge.session.status`
- `google-webmcp-cli auth.get`
- if the session is not ready, start bootstrap or switch to headed:
- `google-webmcp-cli bridge.session.bootstrap`
- `google-webmcp-cli bridge.session.mode.set '{"mode":"headed"}'`
- `google-webmcp-cli bridge.open`
4. Use search tools for public search results:
- `google-webmcp-cli search.web '{"query":"playwright browser automation","limit":10}'`
- `google-webmcp-cli page.get`
5. Use Gemini through the same authenticated browser profile:
- text: `google-webmcp-cli gemini.chat '{"prompt":"Summarize these results","mode":"text","timeoutMs":180000}'`
- image: `google-webmcp-cli gemini.chat '{"prompt":"a watercolor fox reading documentation","mode":"image","timeoutMs":300000}'`
- download current visible images: `google-webmcp-cli gemini.image.download '{"limit":4,"timeoutMs":120000}'`
6. Use debug and navigation helpers only when necessary:
- `google-webmcp-cli page.navigate '{"url":"https://gemini.google.com/app"}'`
- `google-webmcp-cli page.inspect '{"limit":20}'`
7. Parse JSON output only:
- success path: `.ok == true`, consume `.data`
- failure path: `.ok == false`, inspect `.error.code` and `.error.message`
## Default Target
The built-in preset uses:
```bash
--site google
```
The default profile path is:
```bash
~/.uxc/webmcp-profile/google
```
Refresh the link with:
```bash
skills/google-webmcp/scripts/ensure-links.sh
```
## Guardrails
- Keep the Google profile isolated from other sites.
- Google uses `bootstrap_then_attach`; do not expect Gemini tools to work until the managed profile is authenticated.
- Prefer explicit `bridge.session.mode.set` over relaunching the command to change runtime mode.
- Long Gemini generations can legitimately take minutes. Increase `timeoutMs` instead of spawning parallel retries.
- `gemini.image.download` works on visible generated images in the current or target conversation. Do not assume it can recover images that are no longer visible.
- `page.navigate` must stay on Google-owned hosts only.
- If the user closes the visible Google window manually, the headed owner session ends. Run `google-webmcp-cli bridge.open` again if you still need a visible session on the same profile.
## References
- Common command patterns:
- `references/usage-patterns.md`
- Link creation helper:
- `scripts/ensure-links.sh`
FILE:agents/openai.yaml
interface:
display_name: "Google WebMCP"
short_description: "Operate Google Search and Gemini through local-mcp"
default_prompt: "Use $google-webmcp to connect to Google through the built-in adapter, verify auth state, and run Google Search or Gemini tools through local-mcp."
policy:
allow_implicit_invocation: true
FILE:references/usage-patterns.md
# Usage Patterns
## Create or refresh the Google link
```bash
command -v google-webmcp-cli
skills/google-webmcp/scripts/ensure-links.sh
google-webmcp-cli bridge.session.status
```
## Authenticate the managed Google profile
```bash
google-webmcp-cli auth.get
google-webmcp-cli bridge.session.bootstrap
google-webmcp-cli bridge.session.mode.set '{"mode":"headed"}'
google-webmcp-cli bridge.open
```
## Search the web
```bash
google-webmcp-cli search.web '{"query":"playwright browser automation","limit":10}'
```
## Chat with Gemini
```bash
google-webmcp-cli gemini.chat '{"prompt":"Summarize these results","mode":"text","timeoutMs":180000}'
google-webmcp-cli gemini.chat '{"prompt":"a watercolor fox reading documentation","mode":"image","timeoutMs":300000}'
```
## Download generated images
```bash
google-webmcp-cli gemini.image.download '{"limit":4,"timeoutMs":120000}'
```
FILE:scripts/ensure-links.sh
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "BASH_SOURCE[0]")/../../.." && pwd)"
filtered_args=()
while (($#)); do
case "$1" in
--name|--site|--adapter-module|--url)
shift
if (($#)) && [[ "$1" != --* ]]; then
shift
fi
;;
--name=*|--site=*|--adapter-module=*|--url=*)
shift
;;
*)
filtered_args+=("$1")
shift
;;
esac
done
if ((#filtered_args[@] > 0)); then
exec "ROOT_DIR/skills/webmcp-bridge/scripts/ensure-links.sh" --name google --site google "filtered_args[@]"
fi
exec "ROOT_DIR/skills/webmcp-bridge/scripts/ensure-links.sh" --name google --site google
FILE:scripts/validate.sh
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "BASH_SOURCE[0]")/../../.." && pwd)"
SKILL_DIR="ROOT_DIR/skills/google-webmcp"
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
for f in \
"$SKILL_FILE" \
"$OPENAI_FILE" \
"SKILL_DIR/references/usage-patterns.md" \
"SKILL_DIR/scripts/ensure-links.sh"; do
[[ -f "$f" ]] || fail "missing required file: $f"
done
rg -q '^name:\s*google-webmcp\s*$' "$SKILL_FILE" || fail 'invalid skill name'
rg -q '^description:\s*.+' "$SKILL_FILE" || fail 'missing description'
rg -q 'command -v google-webmcp-cli' "$SKILL_FILE" || fail 'missing link-first check'
rg -q 'google-webmcp-cli -h' "$SKILL_FILE" || fail 'missing help-first usage'
rg -q 'gemini.chat -h' "$SKILL_FILE" || fail 'missing Gemini help example'
rg -q 'bridge.session.bootstrap' "$SKILL_FILE" || fail 'missing bootstrap guidance'
rg -q 'bridge.session.mode.set' "$SKILL_FILE" || fail 'missing session mode guidance'
rg -q '~/.uxc/webmcp-profile/google' "$SKILL_FILE" || fail 'missing profile convention'
if rg -q -- '(^|[[:space:]])(list|describe|call)([[:space:]]|$)|--input-json|--args .*[{]' "$SKILL_FILE" "SKILL_DIR/references"; then
fail 'found banned legacy invocation patterns'
fi
echo 'skills/google-webmcp validation passed'
Operate Notion Public API through UXC with a curated OpenAPI schema for search, block traversal, page reads, content writes, and data source/database inspect...
---
name: notion-openapi-skill
description: Operate Notion Public API through UXC with a curated OpenAPI schema for search, block traversal, page reads, content writes, and data source/database inspection. Use when tasks need recursive reads or structured writes that Notion MCP does not expose directly.
---
# Notion Public API Skill
Use this skill to run Notion Public API operations through `uxc` + OpenAPI.
Reuse the `uxc` skill for shared execution, OAuth, and error-handling guidance.
## Prerequisites
- `uxc` is installed and available in `PATH`.
- Network access to `https://api.notion.com/v1`.
- Access to the curated OpenAPI schema URL:
- `https://raw.githubusercontent.com/holon-run/uxc/main/skills/notion-openapi-skill/references/notion-public.openapi.json`
- A Notion integration token or OAuth credential with content read access.
- For writes, the integration also needs the corresponding Notion insert/update content capabilities.
## Scope
This skill covers a read-first Notion REST surface focused on traversal plus common content writes:
- token identity validation
- title search for pages, data sources, and databases
- page lookup
- block lookup
- recursive traversal via block-children pagination
- page property retrieval
- page creation
- page updates, including trash/restore via `in_trash`
- block append
- block updates
- block deletion
- data source retrieval and query
- legacy database retrieval and query
This skill does **not** cover:
- full Notion REST coverage
- comments, file uploads, webhooks, page move, or schema mutation
- automatic recursive traversal loops inside one single command
## Endpoint And Version
- base URL: `https://api.notion.com/v1`
- required version header for this skill: `Notion-Version: 2026-03-11`
The schema is intentionally curated around traversal and schema discovery. It is not a full dump of the Notion API.
## Authentication
Notion Public API requires:
- `Authorization: Bearer <token>`
- `Notion-Version: 2026-03-11`
### Recommended: dedicated REST credential
If you already have an internal integration token:
```bash
uxc auth credential set notion-openapi \
--auth-type api_key \
--header "Authorization=Bearer {{secret}}" \
--header "Notion-Version=2026-03-11" \
--secret-env NOTION_API_TOKEN
uxc auth binding add \
--id notion-openapi \
--host api.notion.com \
--path-prefix /v1 \
--scheme https \
--credential notion-openapi \
--priority 100
```
How to get the internal integration token:
1. Open the Notion integrations dashboard and create an internal integration for your workspace.
2. In the integration configuration page, copy the API secret shown by Notion.
3. In Notion UI, open each target page, data source, or database and add this integration via `Share` or `Connections`.
4. Use that API secret as `NOTION_API_TOKEN` or pass it directly to `uxc auth credential set`.
Without connecting the integration to the target content, REST calls may authenticate successfully but still fail with access errors or return incomplete search results.
If you want OAuth-managed tokens for the REST host:
```bash
uxc auth oauth start notion-openapi \
--endpoint https://api.notion.com/v1 \
--redirect-uri http://127.0.0.1:8788/callback \
--client-id <client_id> \
--scope read
uxc auth oauth complete notion-openapi \
--session-id <session_id> \
--authorization-response 'http://127.0.0.1:8788/callback?code=...'
uxc auth credential set notion-openapi \
--auth-type oauth \
--header "Authorization=Bearer {{secret}}" \
--header "Notion-Version=2026-03-11"
uxc auth binding add \
--id notion-openapi \
--host api.notion.com \
--path-prefix /v1 \
--scheme https \
--credential notion-openapi \
--priority 100
```
### Advanced: reuse the same OAuth credential as `notion-mcp`
This is technically possible in `uxc` if the existing credential already has a valid Notion OAuth access token.
Important:
- once an OAuth credential uses custom headers, include `Authorization=Bearer {{secret}}` explicitly
- adding `Notion-Version=2026-03-11` on the shared credential means the same header will also be sent to `mcp.notion.com/mcp`
- that extra header is expected to be harmless, but this is an interoperability assumption rather than an explicit Notion guarantee
Shared-credential setup:
```bash
uxc auth credential set notion-mcp \
--auth-type oauth \
--header "Authorization=Bearer {{secret}}" \
--header "Notion-Version=2026-03-11"
uxc auth binding add \
--id notion-openapi-shared \
--host api.notion.com \
--path-prefix /v1 \
--scheme https \
--credential notion-mcp \
--priority 100
```
Validate the effective mapping when auth looks wrong:
```bash
uxc auth binding match https://api.notion.com/v1
```
## Core Workflow
1. Use the fixed link command by default:
- `command -v notion-openapi-cli`
- If missing, create it:
`uxc link notion-openapi-cli https://api.notion.com/v1 --schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/notion-openapi-skill/references/notion-public.openapi.json`
- `notion-openapi-cli -h`
2. Inspect operation schema first:
- `notion-openapi-cli post:/search -h`
- `notion-openapi-cli get:/blocks/{block_id}/children -h`
- `notion-openapi-cli post:/pages -h`
- `notion-openapi-cli patch:/blocks/{block_id}/children -h`
- `notion-openapi-cli post:/data_sources/{data_source_id}/query -h`
3. Prefer read validation before broader traversal:
- `notion-openapi-cli get:/users/me`
- `notion-openapi-cli post:/search '{"query":"Roadmap","filter":{"property":"object","value":"page"},"page_size":10}'`
- `notion-openapi-cli get:/blocks/{block_id}/children block_id=<uuid> page_size=100`
4. Traverse recursively outside the API call boundary:
- use `get:/blocks/{block_id}/children` page by page
- for every returned child block with `has_children=true`, call `get:/blocks/{block_id}/children` again on that child ID
5. Use data source or legacy database reads to discover schema before property-sensitive queries:
- `notion-openapi-cli get:/data_sources/{data_source_id} data_source_id=<uuid>`
- `notion-openapi-cli post:/data_sources/{data_source_id}/query data_source_id=<uuid> '{"page_size":25}'`
- `notion-openapi-cli get:/databases/{database_id} database_id=<uuid>`
6. Execute writes only after explicit user confirmation:
- create page: `notion-openapi-cli post:/pages '{...}'`
- append blocks: `notion-openapi-cli patch:/blocks/{block_id}/children '{...}'`
- update page or block: `notion-openapi-cli patch:/pages/{page_id} '{...}'`
- delete block: `notion-openapi-cli delete:/blocks/{block_id} block_id=<uuid>`
## Operation Groups
### Session / Discovery
- `get:/users/me`
- `post:/search`
### Page And Block Traversal
- `get:/pages/{page_id}`
- `get:/pages/{page_id}/properties/{property_id}`
- `get:/blocks/{block_id}`
- `get:/blocks/{block_id}/children`
### Page And Block Writes
- `post:/pages`
- `patch:/pages/{page_id}`
- `patch:/blocks/{block_id}/children`
- `patch:/blocks/{block_id}`
- `delete:/blocks/{block_id}`
### Data Source Reads
- `get:/data_sources/{data_source_id}`
- `post:/data_sources/{data_source_id}/query`
### Legacy Database Reads
- `get:/databases/{database_id}`
- `post:/databases/{database_id}/query`
## Guardrails
- Keep automation on the JSON output envelope; do not use `--text`.
- Parse stable fields first: `ok`, `kind`, `protocol`, `data`, `error`.
- This skill fixes `Notion-Version` at the credential/header layer instead of requiring it as an operation argument. Keep the credential header on `2026-03-11` unless you intentionally migrate the whole skill surface.
- This skill is read-first, but it now includes common content writes. Always confirm intent before `post:/pages`, `patch:/pages/{page_id}`, `patch:/blocks/{block_id}/children`, `patch:/blocks/{block_id}`, or `delete:/blocks/{block_id}`.
- On Notion API version `2026-03-11`, `archived` has been replaced by `in_trash` for request and response semantics. Prefer `in_trash` in update payloads.
- `patch:/blocks/{block_id}/children` supports up to 100 new children in one request and up to two levels of nested blocks in a single payload.
- `patch:/blocks/{block_id}` updates block content, but it does not update child lists. Use `patch:/blocks/{block_id}/children` to append nested content.
- Prefer `data_sources` endpoints over legacy `databases` endpoints for new workflows. Keep legacy database reads only for compatibility with older shared links and IDs.
- `get:/blocks/{block_id}/children` returns only one nesting level at a time. Recursive traversal must be performed by repeated calls.
- Notion may return fewer results than `page_size`; always check `has_more` and `next_cursor`.
- `notion-openapi-cli <operation> ...` is equivalent to `uxc https://api.notion.com/v1 --schema-url <notion_openapi_schema> <operation> ...`.
## References
- Usage patterns: `references/usage-patterns.md`
- Curated OpenAPI schema: `references/notion-public.openapi.json`
- Notion API reference: https://developers.notion.com/reference
- Retrieve a database: https://developers.notion.com/reference/retrieve-a-database
- Retrieve a block: https://developers.notion.com/reference/retrieve-a-block
- Versioning: https://developers.notion.com/reference/versioning
FILE:agents/openai.yaml
agent:
display_name: "Notion Public API"
short_description: "Traverse Notion pages, blocks, and data sources via UXC + OpenAPI"
default_prompt: "Use $notion-openapi-skill to search, traverse, and inspect Notion workspace content through the Notion Public API with UXC, following version-header and read-first guardrails."
FILE:references/notion-public.openapi.json
{
"openapi": "3.0.3",
"info": {
"title": "Notion Public API (Curated Traversal Surface)",
"version": "1.0.0",
"description": "Curated Notion Public API schema for search, block traversal, page reads, and data source inspection in UXC."
},
"servers": [
{
"url": "https://api.notion.com/v1"
}
],
"security": [
{
"bearerAuth": []
}
],
"paths": {
"/users/me": {
"get": {
"operationId": "get:/users/me",
"summary": "Retrieve the bot user for the active token",
"responses": {
"200": {
"description": "Current bot user",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/GenericObject"
}
}
}
}
},
"tags": [
"users"
]
}
},
"/search": {
"post": {
"operationId": "post:/search",
"summary": "Search pages, data sources, and databases by title or object filter",
"requestBody": {
"required": false,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SearchRequest"
}
}
}
},
"responses": {
"200": {
"description": "Search results",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PaginatedObjectList"
}
}
}
}
},
"tags": [
"search"
]
}
},
"/pages/{page_id}": {
"get": {
"operationId": "get:/pages/{page_id}",
"summary": "Retrieve a page by ID",
"parameters": [
{
"name": "page_id",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "filter_properties[]",
"in": "query",
"required": false,
"style": "form",
"explode": true,
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
],
"responses": {
"200": {
"description": "Page object",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/GenericObject"
}
}
}
}
},
"tags": [
"pages"
]
},
"patch": {
"operationId": "patch:/pages/{page_id}",
"summary": "Update page properties, icon, cover, lock state, or trash state",
"parameters": [
{
"name": "page_id",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PageUpdateRequest"
}
}
}
},
"responses": {
"200": {
"description": "Updated page object",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/GenericObject"
}
}
}
}
},
"tags": [
"pages"
]
}
},
"/pages": {
"post": {
"operationId": "post:/pages",
"summary": "Create a page under a page, block, data source, or workspace parent",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PageCreateRequest"
}
}
}
},
"responses": {
"200": {
"description": "Created page object",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/GenericObject"
}
}
}
}
},
"tags": [
"pages"
]
}
},
"/pages/{page_id}/properties/{property_id}": {
"get": {
"operationId": "get:/pages/{page_id}/properties/{property_id}",
"summary": "Retrieve one page property item",
"parameters": [
{
"name": "page_id",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "property_id",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "start_cursor",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "page_size",
"in": "query",
"schema": {
"type": "integer",
"minimum": 1,
"maximum": 100
}
}
],
"responses": {
"200": {
"description": "Page property item response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/GenericObject"
}
}
}
}
},
"tags": [
"pages"
]
}
},
"/blocks/{block_id}": {
"get": {
"operationId": "get:/blocks/{block_id}",
"summary": "Retrieve a block by ID",
"parameters": [
{
"name": "block_id",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Block object",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/GenericObject"
}
}
}
}
},
"tags": [
"blocks"
]
},
"patch": {
"operationId": "patch:/blocks/{block_id}",
"summary": "Update the content or trash state of a block",
"parameters": [
{
"name": "block_id",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/BlockUpdateRequest"
}
}
}
},
"responses": {
"200": {
"description": "Updated block object",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/GenericObject"
}
}
}
}
},
"tags": [
"blocks"
]
},
"delete": {
"operationId": "delete:/blocks/{block_id}",
"summary": "Move a block to trash",
"parameters": [
{
"name": "block_id",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Deleted or trashed block object",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/GenericObject"
}
}
}
}
},
"tags": [
"blocks"
]
}
},
"/blocks/{block_id}/children": {
"get": {
"operationId": "get:/blocks/{block_id}/children",
"summary": "Retrieve one level of child blocks for traversal",
"parameters": [
{
"name": "block_id",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "start_cursor",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "page_size",
"in": "query",
"schema": {
"type": "integer",
"minimum": 1,
"maximum": 100
}
}
],
"responses": {
"200": {
"description": "Paginated child block list",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PaginatedObjectList"
}
}
}
}
},
"tags": [
"blocks"
]
},
"patch": {
"operationId": "patch:/blocks/{block_id}/children",
"summary": "Append child blocks to a parent block, page, or database block",
"parameters": [
{
"name": "block_id",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AppendBlockChildrenRequest"
}
}
}
},
"responses": {
"200": {
"description": "Paginated list of appended first-level blocks",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PaginatedObjectList"
}
}
}
}
},
"tags": [
"blocks"
]
}
},
"/data_sources/{data_source_id}": {
"get": {
"operationId": "get:/data_sources/{data_source_id}",
"summary": "Retrieve a data source by ID",
"parameters": [
{
"name": "data_source_id",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Data source object",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/GenericObject"
}
}
}
}
},
"tags": [
"data_sources"
]
}
},
"/data_sources/{data_source_id}/query": {
"post": {
"operationId": "post:/data_sources/{data_source_id}/query",
"summary": "Query pages contained in a data source",
"parameters": [
{
"name": "data_source_id",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "filter_properties[]",
"in": "query",
"required": false,
"style": "form",
"explode": true,
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
],
"requestBody": {
"required": false,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/DataSourceQueryRequest"
}
}
}
},
"responses": {
"200": {
"description": "Paginated data source results",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PaginatedObjectList"
}
}
}
}
},
"tags": [
"data_sources"
]
}
},
"/databases/{database_id}": {
"get": {
"operationId": "get:/databases/{database_id}",
"summary": "Retrieve a legacy database by ID",
"parameters": [
{
"name": "database_id",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Database object",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/GenericObject"
}
}
}
}
},
"tags": [
"databases"
]
}
},
"/databases/{database_id}/query": {
"post": {
"operationId": "post:/databases/{database_id}/query",
"summary": "Query pages contained in a legacy database",
"parameters": [
{
"name": "database_id",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "filter_properties[]",
"in": "query",
"required": false,
"style": "form",
"explode": true,
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
}
],
"requestBody": {
"required": false,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/DatabaseQueryRequest"
}
}
}
},
"responses": {
"200": {
"description": "Paginated database results",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PaginatedObjectList"
}
}
}
}
},
"tags": [
"databases"
]
}
}
},
"components": {
"securitySchemes": {
"bearerAuth": {
"type": "http",
"scheme": "bearer"
}
},
"schemas": {
"GenericObject": {
"type": "object",
"additionalProperties": true
},
"PaginatedObjectList": {
"type": "object",
"properties": {
"object": {
"type": "string"
},
"type": {
"type": "string"
},
"has_more": {
"type": "boolean"
},
"next_cursor": {
"type": [
"string",
"null"
]
},
"results": {
"type": "array",
"items": {
"$ref": "#/components/schemas/GenericObject"
}
}
},
"additionalProperties": true
},
"SearchRequest": {
"type": "object",
"properties": {
"query": {
"type": "string"
},
"sort": {
"$ref": "#/components/schemas/GenericObject"
},
"filter": {
"$ref": "#/components/schemas/GenericObject"
},
"start_cursor": {
"type": "string"
},
"page_size": {
"type": "integer",
"minimum": 1,
"maximum": 100
}
},
"additionalProperties": true
},
"DataSourceQueryRequest": {
"type": "object",
"properties": {
"filter": {
"$ref": "#/components/schemas/GenericObject"
},
"sorts": {
"type": "array",
"items": {
"$ref": "#/components/schemas/GenericObject"
}
},
"start_cursor": {
"type": "string"
},
"page_size": {
"type": "integer",
"minimum": 1,
"maximum": 100
},
"in_trash": {
"type": "boolean"
},
"result_type": {
"type": "string",
"enum": [
"page",
"data_source"
]
}
},
"additionalProperties": true
},
"DatabaseQueryRequest": {
"type": "object",
"properties": {
"filter": {
"$ref": "#/components/schemas/GenericObject"
},
"sorts": {
"type": "array",
"items": {
"$ref": "#/components/schemas/GenericObject"
}
},
"start_cursor": {
"type": "string"
},
"page_size": {
"type": "integer",
"minimum": 1,
"maximum": 100
},
"in_trash": {
"type": "boolean"
}
},
"additionalProperties": true
},
"PositionObject": {
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": [
"end",
"start",
"after_block"
]
},
"after_block": {
"type": "object",
"properties": {
"id": {
"type": "string"
}
},
"required": [
"id"
],
"additionalProperties": true
}
},
"additionalProperties": true
},
"PageCreateRequest": {
"type": "object",
"properties": {
"parent": {
"$ref": "#/components/schemas/GenericObject"
},
"properties": {
"$ref": "#/components/schemas/GenericObject"
},
"children": {
"type": "array",
"items": {
"$ref": "#/components/schemas/GenericObject"
},
"maxItems": 100
},
"icon": {
"$ref": "#/components/schemas/GenericObject"
},
"cover": {
"$ref": "#/components/schemas/GenericObject"
},
"template": {
"$ref": "#/components/schemas/GenericObject"
}
},
"required": [
"parent",
"properties"
],
"additionalProperties": true
},
"PageUpdateRequest": {
"type": "object",
"properties": {
"properties": {
"$ref": "#/components/schemas/GenericObject"
},
"icon": {
"$ref": "#/components/schemas/GenericObject"
},
"cover": {
"$ref": "#/components/schemas/GenericObject"
},
"is_locked": {
"type": "boolean"
},
"in_trash": {
"type": "boolean"
}
},
"additionalProperties": true
},
"AppendBlockChildrenRequest": {
"type": "object",
"properties": {
"children": {
"type": "array",
"items": {
"$ref": "#/components/schemas/GenericObject"
},
"maxItems": 100
},
"position": {
"$ref": "#/components/schemas/PositionObject"
}
},
"required": [
"children"
],
"additionalProperties": true
},
"BlockUpdateRequest": {
"type": "object",
"properties": {
"type": {
"type": "string"
},
"in_trash": {
"type": "boolean"
}
},
"additionalProperties": true
}
}
}
}
FILE:references/usage-patterns.md
# Notion Public API Skill - Usage Patterns
All commands below assume the credential injects both:
- `Authorization: Bearer <token>`
- `Notion-Version: 2026-03-11`
## Link Setup
```bash
command -v notion-openapi-cli
uxc link notion-openapi-cli https://api.notion.com/v1 \
--schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/notion-openapi-skill/references/notion-public.openapi.json
notion-openapi-cli -h
```
## Auth Setup
Existing internal integration token:
```bash
uxc auth credential set notion-openapi \
--auth-type api_key \
--header "Authorization=Bearer {{secret}}" \
--header "Notion-Version=2026-03-11" \
--secret-env NOTION_API_TOKEN
uxc auth binding add \
--id notion-openapi \
--host api.notion.com \
--path-prefix /v1 \
--scheme https \
--credential notion-openapi \
--priority 100
```
Internal integration token source:
- Create an internal integration in Notion's integrations dashboard.
- Copy the API secret from the integration configuration page.
- Connect that integration to each target page, data source, or database in Notion UI.
- Export it as `NOTION_API_TOKEN` or substitute the secret directly in the credential command.
Shared OAuth credential from Notion MCP:
```bash
uxc auth credential set notion-mcp \
--auth-type oauth \
--header "Authorization=Bearer {{secret}}" \
--header "Notion-Version=2026-03-11"
uxc auth binding add \
--id notion-openapi-shared \
--host api.notion.com \
--path-prefix /v1 \
--scheme https \
--credential notion-mcp \
--priority 100
```
## Read Examples
```bash
# Validate token identity
notion-openapi-cli get:/users/me
# Search pages by title
notion-openapi-cli post:/search \
'{"query":"Roadmap","filter":{"property":"object","value":"page"},"page_size":10}'
# Retrieve one page
notion-openapi-cli get:/pages/{page_id} page_id=<page_uuid>
# Retrieve one block
notion-openapi-cli get:/blocks/{block_id} block_id=<block_uuid>
# List one level of child blocks
notion-openapi-cli get:/blocks/{block_id}/children \
block_id=<block_uuid> \
page_size=100
# Continue block traversal with a pagination cursor
notion-openapi-cli get:/blocks/{block_id}/children \
block_id=<block_uuid> \
page_size=100 \
start_cursor=<cursor>
# Read one page property item
notion-openapi-cli get:/pages/{page_id}/properties/{property_id} \
page_id=<page_uuid> \
property_id=<property_id_or_name>
# Read current data source schema
notion-openapi-cli get:/data_sources/{data_source_id} data_source_id=<data_source_uuid>
# Query pages in a data source
notion-openapi-cli post:/data_sources/{data_source_id}/query \
data_source_id=<data_source_uuid> \
'{"page_size":25}'
# Query a data source with filter + sort
notion-openapi-cli post:/data_sources/{data_source_id}/query \
data_source_id=<data_source_uuid> \
'{"filter":{"property":"Status","status":{"equals":"In progress"}},"sorts":[{"property":"Updated time","direction":"descending"}],"page_size":25}'
# Compatibility path for older database-based workflows
notion-openapi-cli get:/databases/{database_id} database_id=<database_uuid>
```
## Write Examples (Confirm Intent First)
```bash
# Create a page under a parent page
notion-openapi-cli post:/pages \
'{"parent":{"page_id":"<parent_page_uuid>"},"properties":{"title":[{"text":{"content":"Draft from UXC"}}]}}'
# Create a page under a data source
notion-openapi-cli post:/pages \
'{"parent":{"data_source_id":"<data_source_uuid>"},"properties":{"Name":{"title":[{"text":{"content":"Task from UXC"}}]}}}'
# Update page properties or trash state
notion-openapi-cli patch:/pages/{page_id} \
page_id=<page_uuid> \
'{"properties":{"Status":{"status":{"name":"In progress"}}},"in_trash":false}'
# Append paragraph blocks to a page or block
notion-openapi-cli patch:/blocks/{block_id}/children \
block_id=<parent_block_or_page_uuid> \
'{"children":[{"object":"block","type":"paragraph","paragraph":{"rich_text":[{"type":"text","text":{"content":"Hello from UXC"}}]}}]}'
# Append after a specific sibling using 2026-03-11 position syntax
notion-openapi-cli patch:/blocks/{block_id}/children \
block_id=<parent_block_uuid> \
'{"children":[{"object":"block","type":"to_do","to_do":{"rich_text":[{"type":"text","text":{"content":"Follow-up item"}}]}}],"position":{"type":"after_block","after_block":{"id":"<sibling_block_uuid>"}}}'
# Update one block's content
notion-openapi-cli patch:/blocks/{block_id} \
block_id=<block_uuid> \
'{"paragraph":{"rich_text":[{"type":"text","text":{"content":"Updated paragraph text"}}]}}'
# Delete (trash/archive) a block
notion-openapi-cli delete:/blocks/{block_id} block_id=<block_uuid>
```
## Recursive Traversal Pattern
```bash
# 1. Retrieve one parent block or page
notion-openapi-cli get:/blocks/{block_id} block_id=<root_block_uuid>
# 2. Retrieve its first-level children
notion-openapi-cli get:/blocks/{block_id}/children block_id=<root_block_uuid> page_size=100
# 3. For each returned child block where has_children=true, call:
notion-openapi-cli get:/blocks/{block_id}/children block_id=<child_block_uuid> page_size=100
```
## Fallback Equivalence
- `notion-openapi-cli <operation> ...` is equivalent to
`uxc https://api.notion.com/v1 --schema-url <notion_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/notion-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/notion-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["/blocks/{block_id}/children"] and .paths["/data_sources/{data_source_id}/query"] and .paths["/databases/{database_id}"] and .paths["/pages"].post and .paths["/pages/{page_id}"].patch and .paths["/blocks/{block_id}"].patch and .paths["/blocks/{block_id}"].delete and .paths["/blocks/{block_id}/children"].patch' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'OpenAPI schema missing expected traversal, write, or compatibility paths'
jq -e '.components.parameters == null or .components.parameters.NotionVersion == null' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'Notion-Version should not remain as an OpenAPI operation parameter in this skill'
rg -q '^name:\s*notion-openapi-skill\s*$' "SKILL_FILE" || fail 'invalid skill name'
rg -q '^description:\s*.+' "SKILL_FILE" || fail 'missing description'
rg -q 'command -v notion-openapi-cli' "SKILL_FILE" || fail 'missing link-first command check'
rg -q 'uxc link notion-openapi-cli https://api.notion.com/v1 --schema-url ' "SKILL_FILE" || fail 'missing fixed link create command with schema-url'
rg -q 'notion-openapi-cli -h' "SKILL_FILE" || fail 'missing help-first host discovery example'
rg -q 'notion-openapi-cli post:/search -h' "SKILL_FILE" || fail 'missing operation-level help example'
rg -Fq 'notion-openapi-cli post:/pages -h' "SKILL_FILE" || fail 'missing page-create help example'
rg -Fq 'notion-openapi-cli patch:/blocks/{block_id}/children -h' "SKILL_FILE" || fail 'missing block-append help example'
rg -Fq 'Notion-Version=2026-03-11' "SKILL_FILE" "USAGE_FILE" || fail 'missing required Notion-Version guidance'
rg -Fq 'Authorization=Bearer {{secret}}' "SKILL_FILE" "USAGE_FILE" || fail 'missing explicit Authorization header guidance'
rg -q 'notion-mcp' "SKILL_FILE" || fail 'missing shared oauth credential guidance'
rg -q 'read-first' "SKILL_FILE" || fail 'missing read-first guardrail'
rg -Fq 'delete:/blocks/{block_id}' "SKILL_FILE" "USAGE_FILE" || fail 'missing delete block guidance'
rg -Fq 'patch:/pages/{page_id}' "SKILL_FILE" "USAGE_FILE" || fail 'missing update page 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*"Notion Public 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*".*\$notion-openapi-skill.*"\s*$' "OPENAI_FILE" || fail 'default_prompt must mention $notion-openapi-skill'
echo "skills/notion-openapi-skill validation passed"
Operate Nodit Web3 Data API reads through UXC with a curated OpenAPI schema, API-key auth, and overlap-aware guardrails.
---
name: nodit-openapi-skill
description: Operate Nodit Web3 Data API reads through UXC with a curated OpenAPI schema, API-key auth, and overlap-aware guardrails.
---
# Nodit Web3 Data API Skill
Use this skill to run Nodit Web3 Data 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://web3.nodit.io`.
- Network access to `https://raw.githubusercontent.com` when using the hosted schema URL directly.
- Access to the curated OpenAPI schema URL:
- `https://raw.githubusercontent.com/holon-run/uxc/main/skills/nodit-openapi-skill/references/nodit-web3.openapi.json`
- A Nodit API key.
## Scope
This skill covers a read-first Nodit Web3 Data API surface:
- multichain entity lookup
- native balance lookup
- account transaction history
- token contract metadata lookup
- token price lookup by contracts
This skill does **not** cover:
- transaction submission
- full JSON-RPC node compatibility
- every Nodit product surface
- broad coverage of chain-specific APIs beyond the selected v1 reads
## Authentication
Nodit uses `X-API-KEY` header auth.
Configure one API-key credential and bind it to `web3.nodit.io`:
```bash
uxc auth credential set nodit \
--auth-type api_key \
--api-key-header X-API-KEY \
--secret-env NODIT_API_KEY
uxc auth binding add \
--id nodit \
--host web3.nodit.io \
--scheme https \
--credential nodit \
--priority 100
```
Validate the active mapping when auth looks wrong:
```bash
uxc auth binding match https://web3.nodit.io
```
## Core Workflow
1. Use the fixed link command by default:
- `command -v nodit-openapi-cli`
- If missing, create it:
`uxc link nodit-openapi-cli https://web3.nodit.io --schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/nodit-openapi-skill/references/nodit-web3.openapi.json`
- `nodit-openapi-cli -h`
2. Inspect operation schema first:
- `nodit-openapi-cli post:/v1/multichain/lookupEntities -h`
- `nodit-openapi-cli post:/v1/{chain}/{network}/native/getNativeBalanceByAccount -h`
- `nodit-openapi-cli post:/v1/{chain}/{network}/token/getTokenPricesByContracts -h`
3. Prefer narrow reads before broader crawls:
- `nodit-openapi-cli post:/v1/multichain/lookupEntities input=near`
- `nodit-openapi-cli post:/v1/{chain}/{network}/native/getNativeBalanceByAccount chain=ethereum network=mainnet accountAddress=0xd8da6bf26964af9d7eed9e03e53415d37aa96045`
- `nodit-openapi-cli post:/v1/{chain}/{network}/token/getTokenContractMetadataByContracts chain=ethereum network=mainnet contractAddresses:='[\"0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48\"]'`
If `lookupEntities` returns `HTTP 429 TOO_MANY_REQUESTS`, treat it as a plan/tier rate-limit signal rather than an auth failure. Back off and continue with chain-specific reads when you already know the target network.
4. Execute with key/value parameters:
- `nodit-openapi-cli post:/v1/{chain}/{network}/token/getTokenPricesByContracts chain=ethereum network=mainnet contractAddresses:='[\"0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48\"]'`
- `nodit-openapi-cli post:/v1/{chain}/{network}/blockchain/getTransactionsByAccount chain=ethereum network=mainnet accountAddress=0xd8da6bf26964af9d7eed9e03e53415d37aa96045 limit=20`
## Operation Groups
### Discovery
- `post:/v1/multichain/lookupEntities`
### Account And Token Reads
- `post:/v1/{chain}/{network}/native/getNativeBalanceByAccount`
- `post:/v1/{chain}/{network}/blockchain/getTransactionsByAccount`
- `post:/v1/{chain}/{network}/token/getTokenContractMetadataByContracts`
- `post:/v1/{chain}/{network}/token/getTokenPricesByContracts`
## 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.
- Nodit overlaps with `Chainbase`, `Alchemy`, and `Moralis` in some account and token workflows. Prefer Nodit when its multi-chain ergonomics or endpoint shape is a better fit for the task, not by default for every wallet query.
- A concrete good fit is `lookupEntities`, where Nodit can quickly normalize an input string before you decide which chain-specific follow-up read to call.
- `lookupEntities` may hit tight plan limits before other reads do. If you get `HTTP 429 TOO_MANY_REQUESTS`, back off, avoid hot-loop retries, and skip straight to chain-specific reads when the chain is already known.
- Keep `contractAddresses` lists short in v1 and stay well under the documented per-call maximums.
- For long transaction histories, start with small `limit` values and paginate deliberately.
- `nodit-openapi-cli <operation> ...` is equivalent to `uxc https://web3.nodit.io --schema-url <nodit_openapi_schema> <operation> ...`.
## References
- Usage patterns: `references/usage-patterns.md`
- Curated OpenAPI schema: `references/nodit-web3.openapi.json`
- Nodit introduction: https://developer.nodit.io/en/guides/overview/introduction
- Nodit entity lookup docs: https://developer.nodit.io/reference/multichain_lookupentities
- Nodit Web3 Data docs: https://developer.nodit.io/reference/gettransactionsbyaccount
FILE:agents/openai.yaml
interface:
display_name: "Nodit Web3 Data API"
short_description: "Operate Nodit's multichain entity, account, and token reads via UXC + curated OpenAPI schema"
default_prompt: "Use $nodit-openapi-skill to discover and execute Nodit Web3 Data API read-only operations through UXC with X-API-KEY auth and overlap-aware guardrails."
FILE:references/nodit-web3.openapi.json
{
"openapi": "3.0.3",
"info": {
"title": "Nodit Web3 Data API",
"version": "1.0.0",
"description": "Curated Nodit Web3 Data operations for UXC."
},
"servers": [
{
"url": "https://web3.nodit.io"
}
],
"paths": {
"/v1/multichain/lookupEntities": {
"post": {
"operationId": "postLookupEntities",
"summary": "Lookup entities across chains",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"input"
],
"properties": {
"input": {
"type": "string"
}
}
}
}
}
},
"responses": {
"200": {
"description": "Lookup result",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
},
"/v1/{chain}/{network}/native/getNativeBalanceByAccount": {
"post": {
"operationId": "postGetNativeBalanceByAccount",
"summary": "Get native balance by account",
"parameters": [
{
"name": "chain",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "network",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"accountAddress"
],
"properties": {
"accountAddress": {
"type": "string"
}
}
}
}
}
},
"responses": {
"200": {
"description": "Native balance result",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
},
"/v1/{chain}/{network}/blockchain/getTransactionsByAccount": {
"post": {
"operationId": "postGetTransactionsByAccount",
"summary": "Get transactions by account",
"parameters": [
{
"name": "chain",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "network",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"accountAddress"
],
"properties": {
"accountAddress": {
"type": "string"
},
"limit": {
"type": "integer"
},
"cursor": {
"type": "string"
}
}
}
}
}
},
"responses": {
"200": {
"description": "Transactions by account result",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
},
"/v1/{chain}/{network}/token/getTokenContractMetadataByContracts": {
"post": {
"operationId": "postGetTokenContractMetadataByContracts",
"summary": "Get token contract metadata by contracts",
"parameters": [
{
"name": "chain",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "network",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"contractAddresses"
],
"properties": {
"contractAddresses": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
}
},
"responses": {
"200": {
"description": "Token contract metadata result",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
},
"/v1/{chain}/{network}/token/getTokenPricesByContracts": {
"post": {
"operationId": "postGetTokenPricesByContracts",
"summary": "Get token prices by contracts",
"parameters": [
{
"name": "chain",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "network",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"contractAddresses"
],
"properties": {
"contractAddresses": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
}
},
"responses": {
"200": {
"description": "Token prices result",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
}
},
"components": {
"securitySchemes": {
"XApiKey": {
"type": "apiKey",
"in": "header",
"name": "X-API-KEY"
}
},
"schemas": {}
},
"security": [
{
"XApiKey": []
}
]
}
FILE:references/usage-patterns.md
# Nodit Web3 Data API Skill - Usage Patterns
## Link Setup
```bash
command -v nodit-openapi-cli
uxc link nodit-openapi-cli https://web3.nodit.io \
--schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/nodit-openapi-skill/references/nodit-web3.openapi.json
nodit-openapi-cli -h
```
## Auth Setup
```bash
uxc auth credential set nodit \
--auth-type api_key \
--api-key-header X-API-KEY \
--secret-env NODIT_API_KEY
uxc auth binding add \
--id nodit \
--host web3.nodit.io \
--scheme https \
--credential nodit \
--priority 100
```
Validate the binding:
```bash
uxc auth binding match https://web3.nodit.io
```
## Read Examples
```bash
# Identify whether an input string is an account or transaction entity
nodit-openapi-cli post:/v1/multichain/lookupEntities \
input=near
# If this returns HTTP 429 TOO_MANY_REQUESTS, do not treat it as auth failure.
# Back off and continue with chain-specific reads when the target chain is already known.
# Read native balance for an EVM account
nodit-openapi-cli post:/v1/{chain}/{network}/native/getNativeBalanceByAccount \
chain=ethereum \
network=mainnet \
accountAddress=0xd8da6bf26964af9d7eed9e03e53415d37aa96045
# Read recent transactions for an account
nodit-openapi-cli post:/v1/{chain}/{network}/blockchain/getTransactionsByAccount \
chain=ethereum \
network=mainnet \
accountAddress=0xd8da6bf26964af9d7eed9e03e53415d37aa96045 \
limit=20
# Read token contract metadata
nodit-openapi-cli post:/v1/{chain}/{network}/token/getTokenContractMetadataByContracts \
chain=ethereum \
network=mainnet \
contractAddresses:='["0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"]'
# Read token prices by contracts
nodit-openapi-cli post:/v1/{chain}/{network}/token/getTokenPricesByContracts \
chain=ethereum \
network=mainnet \
contractAddresses:='["0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"]'
```
## Fallback Equivalence
- `nodit-openapi-cli <operation> ...` is equivalent to
`uxc https://web3.nodit.io --schema-url <nodit_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/nodit-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/nodit-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/multichain/lookupEntities"] and .paths["/v1/{chain}/{network}/native/getNativeBalanceByAccount"] and .paths["/v1/{chain}/{network}/blockchain/getTransactionsByAccount"]' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'OpenAPI schema missing expected Nodit paths'
jq -e '.paths["/v1/{chain}/{network}/token/getTokenPricesByContracts"].post and .paths["/v1/{chain}/{network}/token/getTokenContractMetadataByContracts"].post' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'OpenAPI schema must expose expected POST operations'
rg -q '^name:\s*nodit-openapi-skill\s*$' "SKILL_FILE" || fail 'invalid skill name'
rg -q '^description:\s*.+' "SKILL_FILE" || fail 'missing description'
rg -q 'command -v nodit-openapi-cli' "SKILL_FILE" || fail 'missing link-first command check'
rg -q 'uxc link nodit-openapi-cli https://web3.nodit.io --schema-url ' "SKILL_FILE" || fail 'missing fixed link create command with schema-url'
rg -F -q 'nodit-openapi-cli post:/v1/multichain/lookupEntities -h' "SKILL_FILE" || fail 'missing operation-level help example'
rg -q -- '--api-key-header X-API-KEY' "SKILL_FILE" || fail 'missing api key setup'
rg -q 'overlaps with `Chainbase`, `Alchemy`, and `Moralis`' "SKILL_FILE" || fail 'missing overlap guardrail'
rg -q 'HTTP 429 TOO_MANY_REQUESTS' "SKILL_FILE" "USAGE_FILE" || fail 'missing rate-limit 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*"Nodit 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*".*\$nodit-openapi-skill.*"\s*$' "OPENAI_FILE" || fail 'default_prompt must mention $nodit-openapi-skill'
echo "skills/nodit-openapi-skill validation passed"
Operate NEAR JSON-RPC reads through UXC with a public provider default, provider-override guidance, and read-only guardrails.
---
name: near-jsonrpc-skill
description: Operate NEAR JSON-RPC reads through UXC with a public provider default, provider-override guidance, and read-only guardrails.
---
# NEAR JSON-RPC Skill
Use this skill to run NEAR 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 a working NEAR RPC provider.
- This skill defaults to `https://free.rpc.fastnear.com`, which is listed on the official NEAR RPC providers page.
- Access to the curated NEAR OpenRPC schema URL:
- `https://raw.githubusercontent.com/holon-run/uxc/main/skills/near-jsonrpc-skill/references/near-public.openrpc.json`
## Scope
This skill covers a safe read-first NEAR RPC surface:
- chain status
- account state query
- finalized block lookup
- chunk lookup by chunk hash
- gas price lookup
- validator set lookup
This skill does **not** cover:
- transaction submission methods
- signing or wallet flows
- archival assumptions for very old blocks or chunks
- deprecated `near.org` or `pagoda.co` public RPC endpoints
## Endpoint And Schema
This skill uses the public FastNear mainnet RPC by default:
- `https://free.rpc.fastnear.com`
The operation surface comes from the curated NEAR OpenRPC schema in this repo:
- `https://raw.githubusercontent.com/holon-run/uxc/main/skills/near-jsonrpc-skill/references/near-public.openrpc.json`
`uxc` JSON-RPC discovery depends on OpenRPC or `rpc.discover`. FastNear does not expose a discoverable method surface that UXC can consume directly, so this skill uses a fixed `--schema-url` link and request flow.
The official NEAR docs now treat `near.org` and `pagoda.co` RPC endpoints as deprecated. Do not use those old hosts as the default for new automation.
If the user already has a preferred provider from the official NEAR providers page, relink the same command to that provider instead of reusing the deprecated endpoints.
## Authentication
The default FastNear public RPC used by this skill does not require authentication.
If the user switches to a private NEAR provider, verify its auth model before reusing this skill unchanged.
## Core Workflow
1. Use the fixed link command by default:
- `command -v near-jsonrpc-cli`
- If missing, create it:
`uxc link near-jsonrpc-cli https://free.rpc.fastnear.com --schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/near-jsonrpc-skill/references/near-public.openrpc.json`
- `near-jsonrpc-cli -h`
2. Inspect operation help first, then run known read methods:
- `near-jsonrpc-cli -h`
- `near-jsonrpc-cli query -h`
- `near-jsonrpc-cli gas_price -h`
- `near-jsonrpc-cli status`
- `near-jsonrpc-cli gas_price --input-json '{"block_id":null}'`
3. Prefer narrow validation before deeper queries:
- `near-jsonrpc-cli status`
- `near-jsonrpc-cli block '{"finality":"final"}'`
- `near-jsonrpc-cli query '{"request_type":"view_account","finality":"final","account_id":"near"}'`
4. Use object JSON for request objects, and `--input-json` when a method expects positional null/default params:
- object request:
`near-jsonrpc-cli chunk '{"chunk_id":"75cewvnKFLrJshoUft1tiUC9GriuxWTc4bWezjy2MoPR"}'`
- positional null/default encoded from an object payload:
`near-jsonrpc-cli gas_price --input-json '{"block_id":null}'`
`near-jsonrpc-cli validators --input-json '{"epoch_reference":null}'`
## Recommended Read Operations
- `status`
- `query`
- `block`
- `chunk`
- `gas_price`
- `validators`
## Guardrails
- Keep automation on the JSON output envelope; do not use `--text`.
- Parse stable fields first: `ok`, `kind`, `protocol`, `data`, `error`.
- Stay on the read-only method surface by default.
- The fixed schema is required because FastNear is not directly discoverable by UXC; do not drop `--schema-url` from the linked command unless the provider proves it exposes usable OpenRPC or `rpc.discover`.
- Do not use this skill for transaction submission, signing, or wallet-authenticated flows.
- The official NEAR docs mark the old `near.org` and `pagoda.co` public RPC endpoints as deprecated. Prefer providers from the official RPC providers page instead.
- Public providers can differ in archival retention and rate limits. If `chunk` or older `block` lookups fail with unknown or garbage-collected errors, switch to a provider that explicitly supports the needed history.
- For methods such as `gas_price` and `validators` that expect positional params, use `--input-json '{"...":null}'` instead of array payloads; UXC CLI positional JSON accepts objects, not arrays.
- `near-jsonrpc-cli <operation> ...` is equivalent to `uxc https://free.rpc.fastnear.com --schema-url <near_openrpc_schema> <operation> ...`.
## References
- Usage patterns: `references/usage-patterns.md`
- Curated OpenRPC schema: `references/near-public.openrpc.json`
- NEAR RPC introduction: https://docs.near.org/api/rpc/introduction
- NEAR RPC providers: https://docs.near.org/api/rpc/providers
FILE:agents/openai.yaml
interface:
display_name: "NEAR JSON-RPC"
short_description: "Operate NEAR mainnet JSON-RPC reads via UXC with a provider-aware public RPC default"
default_prompt: "Use $near-jsonrpc-skill to discover and execute NEAR JSON-RPC read-only operations through UXC with a provider-aware public RPC default and deprecated-endpoint guardrails."
FILE:references/near-public.openrpc.json
{
"openrpc": "1.3.2",
"info": {
"title": "NEAR Public JSON-RPC",
"version": "1.0.0",
"description": "Curated OpenRPC schema for the NEAR read-only methods wrapped by near-jsonrpc-skill."
},
"methods": [
{
"name": "status",
"summary": "Get node and chain status.",
"params": [],
"result": {
"name": "status",
"schema": {
"type": "object"
}
}
},
{
"name": "query",
"summary": "Run a read-only state query with a JSON object request.",
"paramStructure": "by-name",
"params": [
{
"name": "request_type",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "finality",
"schema": {
"type": [
"string",
"null"
]
}
},
{
"name": "block_id",
"schema": {}
},
{
"name": "account_id",
"schema": {
"type": "string"
}
},
{
"name": "method_name",
"schema": {
"type": "string"
}
},
{
"name": "args_base64",
"schema": {
"type": "string"
}
},
{
"name": "prefix_base64",
"schema": {
"type": "string"
}
},
{
"name": "public_key",
"schema": {
"type": "string"
}
},
{
"name": "include_proof",
"schema": {
"type": "boolean"
}
}
],
"result": {
"name": "query_result",
"schema": {
"type": "object"
}
}
},
{
"name": "block",
"summary": "Get block details by finality, height, or hash.",
"paramStructure": "by-name",
"params": [
{
"name": "finality",
"schema": {
"type": "string"
}
},
{
"name": "block_id",
"schema": {}
}
],
"result": {
"name": "block",
"schema": {
"type": "object"
}
}
},
{
"name": "chunk",
"summary": "Get chunk details by chunk id.",
"paramStructure": "by-name",
"params": [
{
"name": "chunk_id",
"required": true,
"schema": {}
}
],
"result": {
"name": "chunk",
"schema": {
"type": "object"
}
}
},
{
"name": "gas_price",
"summary": "Get gas price for the latest block or a specific block.",
"paramStructure": "by-position",
"params": [
{
"name": "block_id",
"schema": {}
}
],
"result": {
"name": "gas_price",
"schema": {
"type": "object"
}
}
},
{
"name": "validators",
"summary": "Get validator information for the latest epoch or a specific epoch reference.",
"paramStructure": "by-position",
"params": [
{
"name": "epoch_reference",
"schema": {}
}
],
"result": {
"name": "validators",
"schema": {
"type": "object"
}
}
}
]
}
FILE:references/usage-patterns.md
# NEAR JSON-RPC Skill - Usage Patterns
## Link Setup
```bash
command -v near-jsonrpc-cli
uxc link near-jsonrpc-cli https://free.rpc.fastnear.com \
--schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/near-jsonrpc-skill/references/near-public.openrpc.json
near-jsonrpc-cli -h
```
## Read Examples
```bash
# Read node and chain status
near-jsonrpc-cli status
# Read the latest finalized block
near-jsonrpc-cli block '{"finality":"final"}'
# Read an account state
near-jsonrpc-cli query '{"request_type":"view_account","finality":"final","account_id":"near"}'
# Read gas price for the latest block context
near-jsonrpc-cli gas_price --input-json '{"block_id":null}'
# Read validator sets
near-jsonrpc-cli validators --input-json '{"epoch_reference":null}'
# Read a chunk by chunk hash
near-jsonrpc-cli chunk '{"chunk_id":"75cewvnKFLrJshoUft1tiUC9GriuxWTc4bWezjy2MoPR"}'
```
## Provider Override
```bash
# Relink the same command to another provider from the official NEAR RPC providers page
uxc link near-jsonrpc-cli https://<near-rpc-provider-host> \
--schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/near-jsonrpc-skill/references/near-public.openrpc.json
```
Do not relink to deprecated `near.org` or `pagoda.co` public RPC hosts.
If a provider later exposes usable OpenRPC or `rpc.discover`, validate that first before dropping the fixed schema override.
## Fallback Equivalence
- `near-jsonrpc-cli <operation> ...` is equivalent to
`uxc https://free.rpc.fastnear.com --schema-url <near_openrpc_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/near-jsonrpc-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/near-public.openrpc.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*near-jsonrpc-skill\s*$' "SKILL_FILE" || fail 'invalid skill name'
rg -q '^description:\s*.+' "SKILL_FILE" || fail 'missing description'
rg -q 'command -v near-jsonrpc-cli' "SKILL_FILE" || fail 'missing link-first command check'
rg -q 'uxc link near-jsonrpc-cli https://free.rpc.fastnear.com --schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/near-jsonrpc-skill/references/near-public.openrpc.json' "SKILL_FILE" || fail 'missing fixed link create command'
rg -q -- '--schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/near-jsonrpc-skill/references/near-public.openrpc.json' "USAGE_FILE" || fail 'missing fixed schema-url usage example'
rg -q 'fixed `--schema-url` link' "SKILL_FILE" || fail 'missing schema-url discovery note'
rg -q 'near.org' "SKILL_FILE" || fail 'missing deprecated endpoint warning'
rg -q 'status' "SKILL_FILE" || fail 'missing status method guidance'
rg -q 'gas_price' "SKILL_FILE" || fail 'missing gas_price method guidance'
rg -q 'validators' "SKILL_FILE" || fail 'missing validators method guidance'
rg -F -q -- "--input-json '{\"block_id\":null}'" "SKILL_FILE" "USAGE_FILE" || fail 'missing gas_price null input guidance'
rg -q 'read-only' "SKILL_FILE" || fail 'missing read-only guardrail'
if rg -q -- "--args\\s+'\\{|\\[null\\]|uxc https://free\\.rpc\\.fastnear\\.com <operation>" "SKILL_FILE" "USAGE_FILE"; then
fail 'found banned legacy JSON argument pattern'
fi
jq -e '.openrpc and (.methods | length >= 6)' "SCHEMA_FILE" >/dev/null || fail 'invalid near openrpc schema'
rg -q '"name": "status"' "SCHEMA_FILE" || fail 'missing status method in schema'
rg -q '"name": "query"' "SCHEMA_FILE" || fail 'missing query method in schema'
rg -q '"name": "gas_price"' "SCHEMA_FILE" || fail 'missing gas_price method in schema'
rg -q '^\s*display_name:\s*"NEAR 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*".*\$near-jsonrpc-skill.*"\s*$' "OPENAI_FILE" || fail 'default_prompt must mention $near-jsonrpc-skill'
echo "skills/near-jsonrpc-skill validation passed"
Operate mempool.space public Bitcoin and Lightning explorer APIs through UXC with a curated OpenAPI schema, no-auth setup, and read-first guardrails.
---
name: mempool-space-openapi-skill
description: Operate mempool.space public Bitcoin and Lightning explorer APIs through UXC with a curated OpenAPI schema, no-auth setup, and read-first guardrails.
---
# mempool.space API Skill
Use this skill to run mempool.space public Bitcoin and Lightning 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 `https://mempool.space/api`.
- Access to the curated OpenAPI schema URL:
- `https://raw.githubusercontent.com/holon-run/uxc/main/skills/mempool-space-openapi-skill/references/mempool-space-public.openapi.json`
## Scope
This skill covers a read-first mempool.space surface for:
- Bitcoin fee estimation and mempool state reads
- block tip height checks
- address and transaction status reads
- Lightning network search, statistics, node rankings, node detail, and channel reads
This skill does **not** cover:
- transaction broadcast or package submission
- websocket subscriptions
- internal or admin routes
- every Esplora-compatible endpoint exposed by mempool.space
## Authentication
mempool.space public reads in this skill do not require authentication.
## Core Workflow
1. Use the fixed link command by default:
- `command -v mempool-space-openapi-cli`
- If missing, create it:
`uxc link mempool-space-openapi-cli https://mempool.space/api --schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/mempool-space-openapi-skill/references/mempool-space-public.openapi.json`
- `mempool-space-openapi-cli -h`
2. Inspect operation schema first:
- `mempool-space-openapi-cli get:/v1/fees/recommended -h`
- `mempool-space-openapi-cli get:/mempool -h`
- `mempool-space-openapi-cli get:/address/{address} -h`
- `mempool-space-openapi-cli get:/v1/lightning/search -h`
- `mempool-space-openapi-cli get:/v1/lightning/channels/{short_id} -h`
3. Prefer narrow reads before broader scans:
- `mempool-space-openapi-cli get:/v1/fees/recommended`
- `mempool-space-openapi-cli get:/blocks/tip/height`
- `mempool-space-openapi-cli get:/v1/lightning/statistics/latest`
4. Execute with key/value parameters:
- `mempool-space-openapi-cli get:/address/{address} address=bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh`
- `mempool-space-openapi-cli get:/tx/{txid}/status txid=4d5d7f2d5dc69aa68a51887db07dd6d906f31f9141320f9f0b4bab76d735a47f`
- `mempool-space-openapi-cli get:/v1/lightning/search searchText=bfx`
- `mempool-space-openapi-cli get:/v1/lightning/channels public_key=033d8656219478701227199cbd6f670335c8d408a92ae88b962c49d4dc0e83e025 status=active`
- `mempool-space-openapi-cli get:/v1/lightning/channels/{short_id} short_id=835866331763769345`
## Operations
- `get:/v1/fees/recommended`
- `get:/mempool`
- `get:/blocks/tip/height`
- `get:/address/{address}`
- `get:/tx/{txid}/status`
- `get:/v1/lightning/statistics/latest`
- `get:/v1/lightning/search`
- `get:/v1/lightning/nodes/rankings`
- `get:/v1/lightning/nodes/{public_key}`
- `get:/v1/lightning/channels`
- `get:/v1/lightning/channels/{short_id}`
## 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 use `tx/push`, package submission, or internal routes.
- Prefer the curated fee, mempool, and Lightning reads here before dropping to the much larger generic Esplora surface.
- `mempool.space` is a public explorer service, so mempool state and Lightning rankings can move quickly. Re-query instead of assuming cached values remain current.
- For `get:/v1/lightning/channels/{short_id}`, mempool.space currently accepts the channel `id` string even though the route label says `short_id`; prefer values returned by search or node channel listing.
- `mempool-space-openapi-cli <operation> ...` is equivalent to `uxc https://mempool.space/api --schema-url <mempool_space_openapi_schema> <operation> ...`.
## References
- Usage patterns: `references/usage-patterns.md`
- Curated OpenAPI schema: `references/mempool-space-public.openapi.json`
- Official mempool repository: https://github.com/mempool/mempool
FILE:agents/openai.yaml
interface:
display_name: "mempool.space Public API"
short_description: "Operate mempool.space Bitcoin fee, mempool, address, transaction, and Lightning explorer reads via UXC + curated OpenAPI schema"
default_prompt: "Use $mempool-space-openapi-skill to discover and execute mempool.space public Bitcoin and Lightning read-only operations through UXC with public no-auth access and explorer-focused guardrails."
FILE:references/mempool-space-public.openapi.json
{
"openapi": "3.0.3",
"info": {
"title": "mempool.space Public API",
"version": "1.0.0",
"description": "Curated mempool.space public Bitcoin and Lightning explorer operations for UXC."
},
"servers": [
{
"url": "https://mempool.space/api"
}
],
"paths": {
"/v1/fees/recommended": {
"get": {
"operationId": "getRecommendedFees",
"summary": "Get recommended Bitcoin fee rates",
"responses": {
"200": {
"description": "Recommended fee rates",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
},
"/mempool": {
"get": {
"operationId": "getMempoolSummary",
"summary": "Get aggregate mempool state",
"responses": {
"200": {
"description": "Mempool summary",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
},
"/blocks/tip/height": {
"get": {
"operationId": "getBlockTipHeight",
"summary": "Get the current block tip height",
"responses": {
"200": {
"description": "Block tip height",
"content": {
"text/plain": {
"schema": {
"type": "string"
}
}
}
}
}
}
},
"/address/{address}": {
"get": {
"operationId": "getAddressSummary",
"summary": "Get Bitcoin address summary",
"parameters": [
{
"name": "address",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Address summary",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
},
"/tx/{txid}/status": {
"get": {
"operationId": "getTransactionStatus",
"summary": "Get Bitcoin transaction confirmation status",
"parameters": [
{
"name": "txid",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Transaction status",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
},
"/v1/lightning/statistics/latest": {
"get": {
"operationId": "getLatestLightningStatistics",
"summary": "Get latest Lightning network statistics",
"responses": {
"200": {
"description": "Lightning statistics snapshot",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
},
"/v1/lightning/search": {
"get": {
"operationId": "searchLightningNodesAndChannels",
"summary": "Search Lightning nodes and channels",
"parameters": [
{
"name": "searchText",
"in": "query",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Lightning search results",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
},
"/v1/lightning/nodes/rankings": {
"get": {
"operationId": "getLightningNodeRankings",
"summary": "Get top Lightning node rankings",
"responses": {
"200": {
"description": "Lightning node rankings",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
},
"/v1/lightning/nodes/{public_key}": {
"get": {
"operationId": "getLightningNode",
"summary": "Get one Lightning node by public key",
"parameters": [
{
"name": "public_key",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Lightning node detail",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
},
"/v1/lightning/channels": {
"get": {
"operationId": "getLightningChannelsForNode",
"summary": "Get Lightning channels for a node",
"parameters": [
{
"name": "public_key",
"in": "query",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "index",
"in": "query",
"required": false,
"schema": {
"type": "integer",
"minimum": -1
}
},
{
"name": "status",
"in": "query",
"required": false,
"schema": {
"type": "string",
"enum": [
"open",
"active",
"closed"
]
}
}
],
"responses": {
"200": {
"description": "Lightning channels for node",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
}
},
"/v1/lightning/channels/{short_id}": {
"get": {
"operationId": "getLightningChannel",
"summary": "Get one Lightning channel by id",
"parameters": [
{
"name": "short_id",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Lightning channel detail",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
}
},
"components": {
"schemas": {}
}
}
FILE:references/usage-patterns.md
# mempool.space API Skill - Usage Patterns
## Link Setup
```bash
command -v mempool-space-openapi-cli
uxc link mempool-space-openapi-cli https://mempool.space/api \
--schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/mempool-space-openapi-skill/references/mempool-space-public.openapi.json
mempool-space-openapi-cli -h
```
## Read Examples
```bash
# Read current public fee recommendations
mempool-space-openapi-cli get:/v1/fees/recommended
# Read aggregate mempool state
mempool-space-openapi-cli get:/mempool
# Read the current block tip height
mempool-space-openapi-cli get:/blocks/tip/height
# Read summary stats for a Bitcoin address
mempool-space-openapi-cli get:/address/{address} \
address=bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh
# Read whether a transaction is confirmed
mempool-space-openapi-cli get:/tx/{txid}/status \
txid=4d5d7f2d5dc69aa68a51887db07dd6d906f31f9141320f9f0b4bab76d735a47f
# Read latest Lightning network statistics
mempool-space-openapi-cli get:/v1/lightning/statistics/latest
# Search Lightning nodes and channels by alias or id fragment
mempool-space-openapi-cli get:/v1/lightning/search \
searchText=bfx
# Read top Lightning node rankings
mempool-space-openapi-cli get:/v1/lightning/nodes/rankings
# Read one Lightning node
mempool-space-openapi-cli get:/v1/lightning/nodes/{public_key} \
public_key=033d8656219478701227199cbd6f670335c8d408a92ae88b962c49d4dc0e83e025
# Read active channels for a Lightning node
mempool-space-openapi-cli get:/v1/lightning/channels \
public_key=033d8656219478701227199cbd6f670335c8d408a92ae88b962c49d4dc0e83e025 \
status=active
# Read one Lightning channel by id
mempool-space-openapi-cli get:/v1/lightning/channels/{short_id} \
short_id=835866331763769345
```
## Fallback Equivalence
- `mempool-space-openapi-cli <operation> ...` is equivalent to
`uxc https://mempool.space/api --schema-url <mempool_space_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/mempool-space-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/mempool-space-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/fees/recommended"] and .paths["/mempool"] and .paths["/blocks/tip/height"] and .paths["/address/{address}"] and .paths["/tx/{txid}/status"]' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'OpenAPI schema missing expected Bitcoin paths'
jq -e '.paths["/v1/lightning/statistics/latest"] and .paths["/v1/lightning/search"] and .paths["/v1/lightning/nodes/{public_key}"] and .paths["/v1/lightning/channels"] and .paths["/v1/lightning/channels/{short_id}"]' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'OpenAPI schema missing expected Lightning paths'
rg -q '^name:\s*mempool-space-openapi-skill\s*$' "SKILL_FILE" || fail 'invalid skill name'
rg -q '^description:\s*.+' "SKILL_FILE" || fail 'missing description'
rg -q 'command -v mempool-space-openapi-cli' "SKILL_FILE" || fail 'missing link-first command check'
rg -q 'uxc link mempool-space-openapi-cli https://mempool.space/api --schema-url ' "SKILL_FILE" || fail 'missing fixed link create command with schema-url'
rg -F -q 'mempool-space-openapi-cli get:/v1/fees/recommended -h' "SKILL_FILE" || fail 'missing operation-level help example'
rg -q 'Treat this v1 skill as read-only' "SKILL_FILE" || fail 'missing read-only guardrail'
rg -q 'accepts the channel `id` string even though the route label says `short_id`' "SKILL_FILE" || fail 'missing channel id 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*"mempool.space Public 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*".*\$mempool-space-openapi-skill.*"\s*$' "OPENAI_FILE" || fail 'default_prompt must mention $mempool-space-openapi-skill'
echo "skills/mempool-space-openapi-skill validation passed"
Use Hive Intelligence MCP through UXC for broad crypto market, onchain, portfolio, and risk workflows with help-first discovery and convenience-layer guardra...
---
name: hive-mcp-skill
description: Use Hive Intelligence MCP through UXC for broad crypto market, onchain, portfolio, and risk workflows with help-first discovery and convenience-layer guardrails.
---
# Hive Intelligence MCP Skill
Use this skill to run Hive Intelligence MCP operations through `uxc`.
Reuse the `uxc` skill for shared protocol discovery, output parsing, and generic auth handling.
## Prerequisites
- `uxc` is installed and available in `PATH`.
- Network access to `https://hiveintelligence.xyz/mcp`.
- Access to the official Hive MCP documentation:
- `https://hiveintelligence.xyz/crypto-market-data-mcp`
## Scope
This skill covers the official remote Hive MCP surface for:
- category-level endpoint discovery
- crypto market and onchain data discovery
- wallet and portfolio lookup workflows
- security and risk endpoint discovery
- schema inspection for underlying API endpoints
- endpoint invocation through Hive's MCP tool layer
This skill does **not** cover:
- direct replacement of first-party provider integrations
- assuming one Hive endpoint has the same data quality as the underlying provider skill
- write operations without separate explicit review
## Positioning
Hive is an official remote MCP convenience layer.
Use it when a user wants one broad crypto MCP entrypoint quickly.
Do not treat Hive as a substitute for direct provider integrations like `DexScreener`, `Helius`, `Blocknative`, or other first-party skills where long-term provider coverage quality matters.
## Endpoint
Use the official Hive MCP endpoint:
- `https://hiveintelligence.xyz/mcp`
## Authentication
The public help-first flow for this skill works without a local auth bootstrap.
If Hive later introduces auth for higher-tier access, verify the runtime error and bind credentials before extending this skill.
## Core Workflow
1. Use the fixed link command by default:
- `command -v hive-mcp-cli`
- If missing, create it:
`uxc link hive-mcp-cli https://hiveintelligence.xyz/mcp`
- `hive-mcp-cli -h`
2. Discover categories first:
- `hive-mcp-cli get_market_and_price_endpoints`
- `hive-mcp-cli get_onchain_dex_pool_endpoints`
- `hive-mcp-cli get_portfolio_wallet_endpoints`
- `hive-mcp-cli get_security_risk_endpoints`
3. Inspect endpoint schema before invoking:
- `hive-mcp-cli get_api_endpoint_schema endpoint=get_token_price`
- `hive-mcp-cli get_api_endpoint_schema endpoint=get_wallet_portfolio`
4. Invoke only after confirming the schema:
- `hive-mcp-cli invoke_api_endpoint endpoint_name=get_token_price args:='{"symbol":"BTC"}'`
- `hive-mcp-cli invoke_api_endpoint endpoint_name=get_wallet_portfolio args:='{"address":"0xd8da6bf26964af9d7eed9e03e53415d37aa96045"}'`
## Recommended Discovery Operations
- `get_market_and_price_endpoints`
- `get_onchain_dex_pool_endpoints`
- `get_portfolio_wallet_endpoints`
- `get_token_contract_endpoints`
- `get_security_risk_endpoints`
- `get_network_infrastructure_endpoints`
## Guardrails
- Keep automation on the JSON output envelope; do not rely on `--text`.
- Parse stable fields first: `ok`, `kind`, `protocol`, `data`, `error`.
- Treat Hive as a convenience aggregation layer, not as the canonical source when a direct provider skill already exists.
- Always inspect a target endpoint schema with `get_api_endpoint_schema` before calling `invoke_api_endpoint`.
- Keep `invoke_api_endpoint` payloads narrow and explicit; do not guess large nested arg objects.
- If a workflow becomes repetitive on one underlying provider surface, prefer a dedicated first-party skill over routing everything through Hive indefinitely.
- `hive-mcp-cli <operation> ...` is equivalent to `uxc https://hiveintelligence.xyz/mcp <operation> ...`.
## References
- Usage patterns: `references/usage-patterns.md`
- Hive MCP docs: https://hiveintelligence.xyz/crypto-market-data-mcp
FILE:agents/openai.yaml
interface:
display_name: "Hive Intelligence MCP"
short_description: "Use Hive's official remote crypto MCP as a broad discovery and convenience layer via UXC"
default_prompt: "Use $hive-mcp-skill to discover and execute Hive Intelligence MCP operations through UXC as a broad crypto convenience layer, inspecting endpoint schemas before invocation."
FILE:references/usage-patterns.md
# Hive Intelligence MCP Skill - Usage Patterns
## Link Setup
```bash
command -v hive-mcp-cli
uxc link hive-mcp-cli https://hiveintelligence.xyz/mcp
hive-mcp-cli -h
```
## Discovery Examples
```bash
# Discover market-oriented endpoint groups
hive-mcp-cli get_market_and_price_endpoints
# Discover onchain DEX and pool analytics endpoints
hive-mcp-cli get_onchain_dex_pool_endpoints
# Discover wallet and portfolio endpoints
hive-mcp-cli get_portfolio_wallet_endpoints
# Discover token and contract endpoints
hive-mcp-cli get_token_contract_endpoints
# Discover risk and security endpoints
hive-mcp-cli get_security_risk_endpoints
```
## Schema And Invocation
```bash
# Inspect schema before invoking an endpoint
hive-mcp-cli get_api_endpoint_schema endpoint=get_token_price
# Invoke a narrow endpoint after confirming the schema
hive-mcp-cli invoke_api_endpoint \
endpoint_name=get_token_price \
args:='{"symbol":"BTC"}'
```
## Fallback Equivalence
- `hive-mcp-cli <operation> ...` is equivalent to
`uxc https://hiveintelligence.xyz/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/hive-mcp-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*hive-mcp-skill\s*$' "SKILL_FILE" || fail 'invalid skill name'
rg -q '^description:\s*.+' "SKILL_FILE" || fail 'missing description'
rg -q 'command -v hive-mcp-cli' "SKILL_FILE" || fail 'missing link-first command check'
rg -q 'uxc link hive-mcp-cli https://hiveintelligence.xyz/mcp' "SKILL_FILE" "USAGE_FILE" || fail 'missing fixed link create command'
rg -q 'get_market_and_price_endpoints' "SKILL_FILE" || fail 'missing category discovery guidance'
rg -q 'get_api_endpoint_schema' "SKILL_FILE" || fail 'missing schema inspection guidance'
rg -q 'invoke_api_endpoint' "SKILL_FILE" || fail 'missing invoke guidance'
rg -q 'convenience aggregation layer' "SKILL_FILE" || fail 'missing positioning 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*"Hive Intelligence MCP"\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*".*\$hive-mcp-skill.*"\s*$' "OPENAI_FILE" || fail 'default_prompt must mention $hive-mcp-skill'
echo "skills/hive-mcp-skill validation passed"
Operate Helius Wallet API reads through UXC with a curated OpenAPI schema, API-key auth, and read-first guardrails.
---
name: helius-openapi-skill
description: Operate Helius Wallet API reads through UXC with a curated OpenAPI schema, API-key auth, and read-first guardrails.
---
# Helius Wallet API Skill
Use this skill to run Helius Wallet 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.helius.xyz`.
- Access to the curated OpenAPI schema URL:
- `https://raw.githubusercontent.com/holon-run/uxc/main/skills/helius-openapi-skill/references/helius-wallet.openapi.json`
- A Helius API key.
## Scope
This skill covers a read-first Helius Wallet API surface:
- wallet identity lookup
- batch identity lookup
- wallet balances
- wallet history
- wallet transfers
- wallet funding source lookup
This skill does **not** cover:
- Helius RPC, DAS, or WebSocket surfaces
- transaction submission
- webhook setup
- the broader Helius platform beyond the selected wallet intelligence endpoints
## Authentication
Helius accepts API keys by query parameter or header. This skill standardizes on `X-Api-Key` header auth.
Configure one API-key credential and bind it to `api.helius.xyz`:
```bash
uxc auth credential set helius \
--auth-type api_key \
--api-key-header X-Api-Key \
--secret-env HELIUS_API_KEY
uxc auth binding add \
--id helius \
--host api.helius.xyz \
--scheme https \
--credential helius \
--priority 100
```
Validate the active mapping when auth looks wrong:
```bash
uxc auth binding match https://api.helius.xyz
```
## Core Workflow
1. Use the fixed link command by default:
- `command -v helius-openapi-cli`
- If missing, create it:
```bash
uxc link helius-openapi-cli https://api.helius.xyz \
--schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/helius-openapi-skill/references/helius-wallet.openapi.json
```
- `helius-openapi-cli -h`
2. Inspect operation schema first:
- `helius-openapi-cli get:/v1/wallet/{wallet}/identity -h`
- `helius-openapi-cli post:/v1/wallet/batch-identity -h`
- `helius-openapi-cli get:/v1/wallet/{wallet}/balances -h`
3. Prefer narrow validation before broader reads:
- `helius-openapi-cli get:/v1/wallet/{wallet}/identity wallet=HXsKP7wrBWaQ8T2Vtjry3Nj3oUgwYcqq9vrHDM12G664`
- `helius-openapi-cli get:/v1/wallet/{wallet}/funded-by wallet=HXsKP7wrBWaQ8T2Vtjry3Nj3oUgwYcqq9vrHDM12G664`
- `helius-openapi-cli get:/v1/wallet/{wallet}/balances wallet=HXsKP7wrBWaQ8T2Vtjry3Nj3oUgwYcqq9vrHDM12G664 page=1 limit=20 showNative=true`
4. Execute with key/value parameters:
- `helius-openapi-cli post:/v1/wallet/batch-identity addresses:='["HXsKP7wrBWaQ8T2Vtjry3Nj3oUgwYcqq9vrHDM12G664"]'`
- `helius-openapi-cli get:/v1/wallet/{wallet}/history wallet=HXsKP7wrBWaQ8T2Vtjry3Nj3oUgwYcqq9vrHDM12G664 limit=20`
- `helius-openapi-cli get:/v1/wallet/{wallet}/transfers wallet=HXsKP7wrBWaQ8T2Vtjry3Nj3oUgwYcqq9vrHDM12G664 limit=20`
- For `addresses:='[...]'`, keep shell quoting in mind. If your shell mangles that form, pass the JSON array as a bare positional payload instead.
## Operation Groups
### Wallet Identity
- `get:/v1/wallet/{wallet}/identity`
- `post:/v1/wallet/batch-identity`
- `get:/v1/wallet/{wallet}/funded-by`
### Wallet Activity
- `get:/v1/wallet/{wallet}/balances`
- `get:/v1/wallet/{wallet}/history`
- `get:/v1/wallet/{wallet}/transfers`
## 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, transaction sending, or webhooks.
- Helius labels the Wallet API as beta. Expect response shape drift and keep parsers focused on stable fields.
- Start with small `limit` values before paginating large histories or transfer crawls.
- Identity and funded-by lookups can return 404-style misses for unknown wallets; treat that as a data absence case before assuming auth failure.
- `helius-openapi-cli <operation> ...` is equivalent to `uxc https://api.helius.xyz --schema-url <helius_openapi_schema> <operation> ...`.
## References
- Usage patterns: `references/usage-patterns.md`
- Curated OpenAPI schema: `references/helius-wallet.openapi.json`
- Helius authentication docs: https://www.helius.dev/docs/api-reference/authentication
- Helius Wallet API docs: https://www.helius.dev/docs/api-reference/wallet-api
FILE:agents/openai.yaml
interface:
display_name: "Helius Wallet API"
short_description: "Operate Helius Solana wallet intelligence reads via UXC + curated OpenAPI schema"
default_prompt: "Use $helius-openapi-skill to discover and execute Helius Wallet API read-only operations through UXC with X-Api-Key auth and beta-surface guardrails."
FILE:references/helius-wallet.openapi.json
{
"openapi": "3.0.3",
"info": {
"title": "Helius Wallet API",
"version": "1.0.0",
"description": "Curated Helius Wallet API beta operations for UXC."
},
"servers": [
{
"url": "https://api.helius.xyz"
}
],
"paths": {
"/v1/wallet/{wallet}/identity": {
"get": {
"operationId": "getWalletIdentity",
"summary": "Get wallet identity",
"parameters": [
{
"name": "wallet",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Wallet identity",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Identity"
}
}
}
}
}
}
},
"/v1/wallet/batch-identity": {
"post": {
"operationId": "postWalletBatchIdentity",
"summary": "Batch wallet identity lookup",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"addresses"
],
"properties": {
"addresses": {
"type": "array",
"items": {
"type": "string"
},
"minItems": 1
}
}
}
}
}
},
"responses": {
"200": {
"description": "Wallet identities",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Identity"
}
}
}
}
}
}
}
},
"/v1/wallet/{wallet}/balances": {
"get": {
"operationId": "getWalletBalances",
"summary": "Get wallet balances",
"parameters": [
{
"name": "wallet",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "page",
"in": "query",
"schema": {
"type": "integer",
"minimum": 1
}
},
{
"name": "limit",
"in": "query",
"schema": {
"type": "integer",
"minimum": 1,
"maximum": 100
}
},
{
"name": "showZeroBalance",
"in": "query",
"schema": {
"type": "boolean"
}
},
{
"name": "showNative",
"in": "query",
"schema": {
"type": "boolean"
}
},
{
"name": "showNfts",
"in": "query",
"schema": {
"type": "boolean"
}
}
],
"responses": {
"200": {
"description": "Wallet balances",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/BalancesResponse"
}
}
}
}
}
}
},
"/v1/wallet/{wallet}/history": {
"get": {
"operationId": "getWalletHistory",
"summary": "Get wallet history",
"parameters": [
{
"name": "wallet",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "limit",
"in": "query",
"schema": {
"type": "integer",
"minimum": 1,
"maximum": 100
}
},
{
"name": "before",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "type",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "tokenAccounts",
"in": "query",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Wallet history",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PaginatedDataResponse"
}
}
}
}
}
}
},
"/v1/wallet/{wallet}/transfers": {
"get": {
"operationId": "getWalletTransfers",
"summary": "Get wallet transfers",
"parameters": [
{
"name": "wallet",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "limit",
"in": "query",
"schema": {
"type": "integer",
"minimum": 1,
"maximum": 100
}
},
{
"name": "cursor",
"in": "query",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Wallet transfers",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PaginatedDataResponse"
}
}
}
}
}
}
},
"/v1/wallet/{wallet}/funded-by": {
"get": {
"operationId": "getWalletFundedBy",
"summary": "Get wallet funding source",
"parameters": [
{
"name": "wallet",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Wallet funding source",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/FundedBy"
}
}
}
}
}
}
}
},
"components": {
"securitySchemes": {
"XApiKey": {
"type": "apiKey",
"in": "header",
"name": "X-Api-Key"
}
},
"schemas": {
"Identity": {
"type": "object",
"additionalProperties": true,
"properties": {
"address": {
"type": "string"
},
"name": {
"type": "string"
},
"category": {
"type": "string"
},
"type": {
"type": "string"
}
}
},
"BalanceRow": {
"type": "object",
"additionalProperties": true,
"properties": {
"mint": {
"type": "string"
},
"symbol": {
"type": "string"
},
"balance": {
"type": [
"number",
"string",
"null"
]
},
"usdValue": {
"type": [
"number",
"null"
]
},
"pricePerToken": {
"type": [
"number",
"null"
]
}
}
},
"BalancesResponse": {
"type": "object",
"additionalProperties": true,
"properties": {
"wallet": {
"type": "string"
},
"totalUsdValue": {
"type": [
"number",
"null"
]
},
"page": {
"type": "integer"
},
"limit": {
"type": "integer"
},
"balances": {
"type": "array",
"items": {
"$ref": "#/components/schemas/BalanceRow"
}
}
}
},
"PaginatedDataResponse": {
"type": "object",
"additionalProperties": true,
"properties": {
"data": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true
}
},
"pagination": {
"type": "object",
"additionalProperties": true
}
}
},
"FundedBy": {
"type": "object",
"additionalProperties": true,
"properties": {
"funder": {
"type": "string"
},
"funderName": {
"type": "string"
},
"funderType": {
"type": "string"
},
"amount": {
"type": [
"number",
"string",
"null"
]
},
"timestamp": {
"type": [
"integer",
"null"
]
},
"signature": {
"type": "string"
}
}
}
}
},
"security": [
{
"XApiKey": []
}
]
}
FILE:references/usage-patterns.md
# Helius Wallet API Skill - Usage Patterns
## Link Setup
```bash
command -v helius-openapi-cli
uxc link helius-openapi-cli https://api.helius.xyz \
--schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/helius-openapi-skill/references/helius-wallet.openapi.json
helius-openapi-cli -h
```
## Auth Setup
```bash
uxc auth credential set helius \
--auth-type api_key \
--api-key-header X-Api-Key \
--secret-env HELIUS_API_KEY
uxc auth binding add \
--id helius \
--host api.helius.xyz \
--scheme https \
--credential helius \
--priority 100
```
Validate the binding:
```bash
uxc auth binding match https://api.helius.xyz
```
## Read Examples
```bash
# Identify a wallet with a known label
helius-openapi-cli get:/v1/wallet/{wallet}/identity \
wallet=HXsKP7wrBWaQ8T2Vtjry3Nj3oUgwYcqq9vrHDM12G664
# Batch identity lookup for one or more addresses
helius-openapi-cli post:/v1/wallet/batch-identity \
addresses:='["HXsKP7wrBWaQ8T2Vtjry3Nj3oUgwYcqq9vrHDM12G664"]'
# If your shell does not preserve :='[...]' quoting well, pass the same body as bare JSON
helius-openapi-cli post:/v1/wallet/batch-identity \
'{"addresses":["HXsKP7wrBWaQ8T2Vtjry3Nj3oUgwYcqq9vrHDM12G664"]}'
# Read balances with a small page size first
helius-openapi-cli get:/v1/wallet/{wallet}/balances \
wallet=HXsKP7wrBWaQ8T2Vtjry3Nj3oUgwYcqq9vrHDM12G664 \
page=1 \
limit=20 \
showNative=true
# Read recent wallet history
helius-openapi-cli get:/v1/wallet/{wallet}/history \
wallet=HXsKP7wrBWaQ8T2Vtjry3Nj3oUgwYcqq9vrHDM12G664 \
limit=20
# Read recent transfers
helius-openapi-cli get:/v1/wallet/{wallet}/transfers \
wallet=HXsKP7wrBWaQ8T2Vtjry3Nj3oUgwYcqq9vrHDM12G664 \
limit=20
# Discover the wallet's original funding source
helius-openapi-cli get:/v1/wallet/{wallet}/funded-by \
wallet=HXsKP7wrBWaQ8T2Vtjry3Nj3oUgwYcqq9vrHDM12G664
```
## Fallback Equivalence
- `helius-openapi-cli <operation> ...` is equivalent to
`uxc https://api.helius.xyz --schema-url <helius_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/helius-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/helius-wallet.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/wallet/{wallet}/identity"] and .paths["/v1/wallet/batch-identity"] and .paths["/v1/wallet/{wallet}/balances"]' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'OpenAPI schema missing expected Helius wallet paths'
jq -e '.paths["/v1/wallet/batch-identity"].post and .paths["/v1/wallet/{wallet}/history"].get and .paths["/v1/wallet/{wallet}/funded-by"].get' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'OpenAPI schema must expose expected GET/POST operations'
rg -q '^name:\s*helius-openapi-skill\s*$' "SKILL_FILE" || fail 'invalid skill name'
rg -q '^description:\s*.+' "SKILL_FILE" || fail 'missing description'
rg -q 'command -v helius-openapi-cli' "SKILL_FILE" || fail 'missing link-first command check'
rg -q 'uxc link helius-openapi-cli https://api.helius.xyz' "SKILL_FILE" || fail 'missing fixed link create command'
rg -q -- '--schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/helius-openapi-skill/references/helius-wallet.openapi.json' "SKILL_FILE" || fail 'missing schema-url guidance'
rg -F -q 'helius-openapi-cli post:/v1/wallet/batch-identity -h' "SKILL_FILE" || fail 'missing operation-level help example'
rg -q -- '--api-key-header X-Api-Key' "SKILL_FILE" || fail 'missing api key setup'
rg -q 'uxc auth binding match https://api.helius.xyz' "SKILL_FILE" || fail 'missing binding match check'
rg -q 'beta' "SKILL_FILE" || fail 'missing beta surface 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*"Helius Wallet 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*".*\$helius-openapi-skill.*"\s*$' "OPENAI_FILE" || fail 'default_prompt must mention $helius-openapi-skill'
echo "skills/helius-openapi-skill validation passed"
Operate DexScreener public market data APIs through UXC with a curated OpenAPI schema, no-auth setup, and read-first guardrails.
---
name: dexscreener-openapi-skill
description: Operate DexScreener public market data APIs through UXC with a curated OpenAPI schema, no-auth setup, and read-first guardrails.
---
# DexScreener API Skill
Use this skill to run DexScreener 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.dexscreener.com`.
- Access to the curated OpenAPI schema URL:
- `https://raw.githubusercontent.com/holon-run/uxc/main/skills/dexscreener-openapi-skill/references/dexscreener-public.openapi.json`
## Scope
This skill covers a read-first DexScreener surface for:
- token profile discovery
- latest and top token boosts
- pair search by free-text query
- pair lookup by chain and pair address
- token market lookup by chain and token address list
This skill does **not** cover:
- write operations
- private or authenticated workflows
- every DexScreener endpoint
- trading or wallet execution
## Authentication
DexScreener public reads in this skill do not require authentication.
## Core Workflow
1. Use the fixed link command by default:
- `command -v dexscreener-openapi-cli`
- If missing, create it:
`uxc link dexscreener-openapi-cli https://api.dexscreener.com --schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/dexscreener-openapi-skill/references/dexscreener-public.openapi.json`
- `dexscreener-openapi-cli -h`
2. Inspect operation schema first:
- `dexscreener-openapi-cli get:/token-profiles/latest/v1 -h`
- `dexscreener-openapi-cli get:/latest/dex/search -h`
- `dexscreener-openapi-cli get:/latest/dex/pairs/{chainId}/{pairId} -h`
- `dexscreener-openapi-cli get:/tokens/v1/{chainId}/{tokenAddresses} -h`
3. Prefer narrow reads before broader scans:
- `dexscreener-openapi-cli get:/token-profiles/latest/v1`
- `dexscreener-openapi-cli get:/token-boosts/latest/v1`
- `dexscreener-openapi-cli get:/latest/dex/search q=solana`
4. Execute with key/value parameters:
- `dexscreener-openapi-cli get:/latest/dex/pairs/{chainId}/{pairId} chainId=solana pairId=GgzbfpKtozV6Hyiahkh2yNVZBZsJa4pcetCmjNtgEXiM`
- `dexscreener-openapi-cli get:/tokens/v1/{chainId}/{tokenAddresses} chainId=solana tokenAddresses=So11111111111111111111111111111111111111112`
## Operations
- `get:/token-profiles/latest/v1`
- `get:/token-boosts/latest/v1`
- `get:/token-boosts/top/v1`
- `get:/latest/dex/search`
- `get:/latest/dex/pairs/{chainId}/{pairId}`
- `get:/tokens/v1/{chainId}/{tokenAddresses}`
## 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, swaps, or wallet operations.
- Keep `q` focused to a token, pair, chain, or symbol rather than broad crawler-style searches.
- For `tokenAddresses`, start with a single address or a short comma-separated list before scaling up.
- DexScreener enforces endpoint-specific rate limits. Profile and boost endpoints are typically lower-throughput than pair and token lookup endpoints, so cache aggressively when polling discovery feeds.
- DexScreener data is market-observation oriented and may be noisier on long-tail tokens than curated exchange-only feeds.
- `dexscreener-openapi-cli <operation> ...` is equivalent to `uxc https://api.dexscreener.com --schema-url <dexscreener_openapi_schema> <operation> ...`.
## References
- Usage patterns: `references/usage-patterns.md`
- Curated OpenAPI schema: `references/dexscreener-public.openapi.json`
- DexScreener API reference: https://docs.dexscreener.com/api/reference
FILE:agents/openai.yaml
interface:
display_name: "DexScreener API"
short_description: "Operate DexScreener public market and DEX pair reads via UXC + curated OpenAPI schema"
default_prompt: "Use $dexscreener-openapi-skill to discover and execute DexScreener public read-only market data operations through UXC with a curated OpenAPI schema and no-auth setup."
FILE:references/dexscreener-public.openapi.json
{
"openapi": "3.0.3",
"info": {
"title": "DexScreener Public API",
"version": "1.0.0",
"description": "Curated public DexScreener market data operations for UXC."
},
"servers": [
{
"url": "https://api.dexscreener.com"
}
],
"paths": {
"/token-profiles/latest/v1": {
"get": {
"operationId": "getTokenProfilesLatestV1",
"summary": "Get latest token profiles",
"responses": {
"200": {
"description": "Latest token profiles",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/TokenProfile"
}
}
}
}
}
}
}
},
"/token-boosts/latest/v1": {
"get": {
"operationId": "getTokenBoostsLatestV1",
"summary": "Get latest token boosts",
"responses": {
"200": {
"description": "Latest token boosts",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/TokenBoost"
}
}
}
}
}
}
}
},
"/token-boosts/top/v1": {
"get": {
"operationId": "getTokenBoostsTopV1",
"summary": "Get top token boosts",
"responses": {
"200": {
"description": "Top token boosts",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/TokenBoost"
}
}
}
}
}
}
}
},
"/latest/dex/search": {
"get": {
"operationId": "getLatestDexSearch",
"summary": "Search pairs by query",
"parameters": [
{
"name": "q",
"in": "query",
"required": true,
"schema": {
"type": "string"
},
"description": "Free-text token, symbol, or pair query"
}
],
"responses": {
"200": {
"description": "Pair search results",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PairListResponse"
}
}
}
}
}
}
},
"/latest/dex/pairs/{chainId}/{pairId}": {
"get": {
"operationId": "getLatestDexPairsByChainAndPair",
"summary": "Get pair market data by chain and pair address",
"parameters": [
{
"name": "chainId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "pairId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Pair lookup result",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PairListResponse"
}
}
}
}
}
}
},
"/tokens/v1/{chainId}/{tokenAddresses}": {
"get": {
"operationId": "getTokensV1ByChainAndAddresses",
"summary": "Get token market rows by chain and token addresses",
"parameters": [
{
"name": "chainId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "tokenAddresses",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "One token address or a comma-separated list of token addresses"
}
],
"responses": {
"200": {
"description": "Token market rows",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Pair"
}
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"Link": {
"type": "object",
"additionalProperties": true,
"properties": {
"type": {
"type": "string"
},
"label": {
"type": "string"
},
"url": {
"type": "string"
}
}
},
"TokenRef": {
"type": "object",
"additionalProperties": true,
"properties": {
"address": {
"type": "string"
},
"name": {
"type": "string"
},
"symbol": {
"type": "string"
}
}
},
"TokenProfile": {
"type": "object",
"additionalProperties": true,
"properties": {
"chainId": {
"type": "string"
},
"tokenAddress": {
"type": "string"
},
"url": {
"type": "string"
},
"icon": {
"type": "string"
},
"header": {
"type": "string"
},
"description": {
"type": "string"
},
"links": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Link"
}
}
}
},
"TokenBoost": {
"type": "object",
"additionalProperties": true,
"properties": {
"chainId": {
"type": "string"
},
"tokenAddress": {
"type": "string"
},
"url": {
"type": "string"
},
"icon": {
"type": "string"
},
"header": {
"type": "string"
},
"description": {
"type": "string"
},
"amount": {
"type": [
"number",
"null"
]
},
"totalAmount": {
"type": [
"number",
"null"
]
},
"links": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Link"
}
}
}
},
"Pair": {
"type": "object",
"additionalProperties": true,
"properties": {
"chainId": {
"type": "string"
},
"dexId": {
"type": "string"
},
"url": {
"type": "string"
},
"pairAddress": {
"type": "string"
},
"baseToken": {
"$ref": "#/components/schemas/TokenRef"
},
"quoteToken": {
"$ref": "#/components/schemas/TokenRef"
},
"priceNative": {
"type": "string"
},
"priceUsd": {
"type": "string"
},
"liquidity": {
"type": "object",
"additionalProperties": true
},
"fdv": {
"type": [
"number",
"null"
]
},
"marketCap": {
"type": [
"number",
"null"
]
},
"boosts": {
"type": "object",
"additionalProperties": true
}
}
},
"PairListResponse": {
"type": "object",
"additionalProperties": true,
"properties": {
"schemaVersion": {
"type": "string"
},
"pairs": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Pair"
}
}
}
}
}
}
}
FILE:references/usage-patterns.md
# DexScreener API Skill - Usage Patterns
## Link Setup
```bash
command -v dexscreener-openapi-cli
uxc link dexscreener-openapi-cli https://api.dexscreener.com \
--schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/dexscreener-openapi-skill/references/dexscreener-public.openapi.json
dexscreener-openapi-cli -h
```
## Read Examples
```bash
# Read the latest token profile feed
dexscreener-openapi-cli get:/token-profiles/latest/v1
# Read latest boosted tokens
dexscreener-openapi-cli get:/token-boosts/latest/v1
# Read top boosted tokens
dexscreener-openapi-cli get:/token-boosts/top/v1
# Search pairs by query
dexscreener-openapi-cli get:/latest/dex/search q=solana
# Read a specific pair on one chain
dexscreener-openapi-cli get:/latest/dex/pairs/{chainId}/{pairId} \
chainId=solana \
pairId=GgzbfpKtozV6Hyiahkh2yNVZBZsJa4pcetCmjNtgEXiM
# Read token market rows for one token address on one chain
dexscreener-openapi-cli get:/tokens/v1/{chainId}/{tokenAddresses} \
chainId=solana \
tokenAddresses=So11111111111111111111111111111111111111112
```
## Fallback Equivalence
- `dexscreener-openapi-cli <operation> ...` is equivalent to
`uxc https://api.dexscreener.com --schema-url <dexscreener_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/dexscreener-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/dexscreener-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["/token-profiles/latest/v1"] and .paths["/latest/dex/search"] and .paths["/tokens/v1/{chainId}/{tokenAddresses}"]' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'OpenAPI schema missing expected DexScreener paths'
jq -e '.paths["/latest/dex/pairs/{chainId}/{pairId}"].get and .paths["/token-boosts/top/v1"].get' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'OpenAPI schema must expose expected GET operations'
rg -q '^name:\s*dexscreener-openapi-skill\s*$' "SKILL_FILE" || fail 'invalid skill name'
rg -q '^description:\s*.+' "SKILL_FILE" || fail 'missing description'
rg -q 'command -v dexscreener-openapi-cli' "SKILL_FILE" || fail 'missing link-first command check'
rg -q 'uxc link dexscreener-openapi-cli https://api.dexscreener.com --schema-url ' "SKILL_FILE" || fail 'missing fixed link create command with schema-url'
rg -F -q 'dexscreener-openapi-cli get:/latest/dex/search -h' "SKILL_FILE" || fail 'missing operation-level help example'
rg -q 'no-auth setup' "OPENAI_FILE" || fail 'missing no-auth prompt 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*"DexScreener 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*".*\$dexscreener-openapi-skill.*"\s*$' "OPENAI_FILE" || fail 'default_prompt must mention $dexscreener-openapi-skill'
echo "skills/dexscreener-openapi-skill validation passed"
Operate Blocknative gas intelligence APIs through UXC with a curated OpenAPI schema, API-key auth, and read-first guardrails.
---
name: blocknative-openapi-skill
description: Operate Blocknative gas intelligence APIs through UXC with a curated OpenAPI schema, API-key auth, and read-first guardrails.
---
# Blocknative Gas Platform Skill
Use this skill to run Blocknative gas intelligence 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.blocknative.com`.
- Access to the curated OpenAPI schema URL:
- `https://raw.githubusercontent.com/holon-run/uxc/main/skills/blocknative-openapi-skill/references/blocknative-gas.openapi.json`
- A Blocknative API key for the full v1 surface.
## Scope
This skill covers a read-first Blocknative gas intelligence surface:
- supported chain discovery
- gas price confidence estimates
- base fee and blob fee prediction
- pending gas distribution analysis
This skill does **not** cover:
- write operations
- transaction submission
- mempool event streaming
- broader Blocknative product areas outside the selected gas platform endpoints
## Authentication
Blocknative uses `Authorization` header auth. Some discovery and gas reads can work without a key, but this skill standardizes on authenticated requests because `basefee-estimates` and `distribution` require a valid API key.
Configure one API-key credential and bind it to `api.blocknative.com`:
```bash
uxc auth credential set blocknative \
--auth-type api_key \
--api-key-header Authorization \
--secret-env BLOCKNATIVE_API_KEY
uxc auth binding add \
--id blocknative \
--host api.blocknative.com \
--scheme https \
--credential blocknative \
--priority 100
```
Validate the active mapping when auth looks wrong:
```bash
uxc auth binding match https://api.blocknative.com
```
## Core Workflow
1. Use the fixed link command by default:
- `command -v blocknative-openapi-cli`
- If missing, create it:
`uxc link blocknative-openapi-cli https://api.blocknative.com --schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/blocknative-openapi-skill/references/blocknative-gas.openapi.json`
- `blocknative-openapi-cli -h`
2. Inspect operation schema first:
- `blocknative-openapi-cli get:/chains -h`
- `blocknative-openapi-cli get:/gasprices/blockprices -h`
- `blocknative-openapi-cli get:/gasprices/basefee-estimates -h`
3. Prefer narrow validation before broader polling:
- `blocknative-openapi-cli get:/chains`
- `blocknative-openapi-cli get:/gasprices/blockprices chainid=1`
- `blocknative-openapi-cli get:/gasprices/basefee-estimates`
4. Execute with key/value parameters:
- `blocknative-openapi-cli get:/gasprices/blockprices chainid=1 confidenceLevels=70,90,99`
- `blocknative-openapi-cli get:/gasprices/blockprices system=story network=mainnet`
- `blocknative-openapi-cli get:/gasprices/distribution chainid=1`
## Operation Groups
### Discovery
- `get:/chains`
### Gas Intelligence
- `get:/gasprices/blockprices`
- `get:/gasprices/basefee-estimates`
- `get:/gasprices/distribution`
## 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 sending or execution support.
- `blockprices` can be polled without auth on some plans, but `basefee-estimates` and `distribution` require a valid key. Standardize on auth so mixed workflows do not fail mid-run.
- These endpoints update at most once per second on paid plans and more slowly on free plans. For automation, start around one poll every 5 to 10 seconds and only tighten that interval when you specifically need fresher paid-plan data.
- `distribution` is Ethereum-mainnet focused in the current docs. Do not assume multi-chain coverage there just because `blockprices` supports many chains.
- Keep `confidenceLevels` narrow and explicit when you do not need the full default ladder.
- `blocknative-openapi-cli <operation> ...` is equivalent to `uxc https://api.blocknative.com --schema-url <blocknative_openapi_schema> <operation> ...`.
## References
- Usage patterns: `references/usage-patterns.md`
- Curated OpenAPI schema: `references/blocknative-gas.openapi.json`
- Blocknative Gas Price API docs: https://docs.blocknative.com/gas-prediction/gas-platform
- Blocknative Base Fee API docs: https://docs.blocknative.com/gas-prediction/prediction-api-base-fee-and-blob-fee
- Blocknative Gas Distribution API docs: https://docs.blocknative.com/gas-prediction/gas-distribution-api
FILE:agents/openai.yaml
interface:
display_name: "Blocknative Gas Platform"
short_description: "Operate Blocknative gas price and fee intelligence reads via UXC + curated OpenAPI schema"
default_prompt: "Use $blocknative-openapi-skill to discover and execute Blocknative gas intelligence read-only operations through UXC with Authorization header auth and polling guardrails."
FILE:references/blocknative-gas.openapi.json
{
"openapi": "3.0.3",
"info": {
"title": "Blocknative Gas Platform",
"version": "1.0.0",
"description": "Curated Blocknative gas intelligence operations for UXC."
},
"servers": [
{
"url": "https://api.blocknative.com"
}
],
"paths": {
"/chains": {
"get": {
"operationId": "getChains",
"summary": "List supported chains",
"responses": {
"200": {
"description": "Supported chains",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Chain"
}
}
}
}
}
}
}
},
"/gasprices/blockprices": {
"get": {
"operationId": "getGasPriceBlockPrices",
"summary": "Get gas price confidence estimates",
"parameters": [
{
"name": "chainid",
"in": "query",
"schema": {
"type": "integer"
}
},
{
"name": "system",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "network",
"in": "query",
"schema": {
"type": "string"
}
},
{
"name": "confidenceLevels",
"in": "query",
"schema": {
"type": "string"
},
"description": "Comma-separated confidence levels such as 70,90,99"
}
],
"responses": {
"200": {
"description": "Gas price block estimates",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/BlockPricesResponse"
}
}
}
}
}
}
},
"/gasprices/basefee-estimates": {
"get": {
"operationId": "getBaseFeeEstimates",
"summary": "Get base fee and blob fee estimates",
"responses": {
"200": {
"description": "Base fee estimates",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/BaseFeeResponse"
}
}
}
}
}
}
},
"/gasprices/distribution": {
"get": {
"operationId": "getGasDistribution",
"summary": "Get pending gas distribution",
"parameters": [
{
"name": "chainid",
"in": "query",
"schema": {
"type": "integer"
}
}
],
"responses": {
"200": {
"description": "Gas distribution",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/DistributionResponse"
}
}
}
}
}
}
}
},
"components": {
"securitySchemes": {
"AuthorizationHeader": {
"type": "apiKey",
"in": "header",
"name": "Authorization"
}
},
"schemas": {
"Chain": {
"type": "object",
"additionalProperties": true,
"properties": {
"arch": {
"type": "string"
},
"chainId": {
"type": "integer"
},
"label": {
"type": "string"
},
"system": {
"type": "string"
},
"network": {
"type": "string"
},
"features": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"EstimatedPrice": {
"type": "object",
"additionalProperties": true,
"properties": {
"confidence": {
"type": "number"
},
"price": {
"type": "number"
},
"maxPriorityFeePerGas": {
"type": [
"number",
"null"
]
},
"maxFeePerGas": {
"type": [
"number",
"null"
]
}
}
},
"BlockPrice": {
"type": "object",
"additionalProperties": true,
"properties": {
"blockNumber": {
"type": "integer"
},
"estimatedTransactionCount": {
"type": "integer"
},
"baseFeePerGas": {
"type": [
"number",
"null"
]
},
"blobBaseFeePerGas": {
"type": [
"number",
"null"
]
},
"estimatedPrices": {
"type": "array",
"items": {
"$ref": "#/components/schemas/EstimatedPrice"
}
}
}
},
"BlockPricesResponse": {
"type": "object",
"additionalProperties": true,
"properties": {
"system": {
"type": "string"
},
"network": {
"type": "string"
},
"unit": {
"type": "string"
},
"maxPrice": {
"type": "number"
},
"currentBlockNumber": {
"type": "integer"
},
"msSinceLastBlock": {
"type": "integer"
},
"blockPrices": {
"type": "array",
"items": {
"$ref": "#/components/schemas/BlockPrice"
}
}
}
},
"BaseFeeResponse": {
"type": "object",
"additionalProperties": true,
"properties": {
"system": {
"type": "string"
},
"network": {
"type": "string"
},
"unit": {
"type": "string"
},
"currentBlockNumber": {
"type": "integer"
},
"msSinceLastBlock": {
"type": "integer"
},
"baseFeePerGas": {
"type": "number"
},
"blobBaseFeePerGas": {
"type": [
"number",
"null"
]
},
"estimatedBaseFees": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true
}
}
}
},
"DistributionResponse": {
"type": "object",
"additionalProperties": true,
"properties": {
"system": {
"type": "string"
},
"network": {
"type": "string"
},
"unit": {
"type": "string"
},
"maxPrice": {
"type": "number"
},
"currentBlockNumber": {
"type": "integer"
},
"msSinceLastBlock": {
"type": "integer"
},
"topNDistribution": {
"type": "object",
"additionalProperties": true
}
}
}
}
},
"security": [
{
"AuthorizationHeader": []
}
]
}
FILE:references/usage-patterns.md
# Blocknative Gas Platform Skill - Usage Patterns
## Link Setup
```bash
command -v blocknative-openapi-cli
uxc link blocknative-openapi-cli https://api.blocknative.com \
--schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/blocknative-openapi-skill/references/blocknative-gas.openapi.json
blocknative-openapi-cli -h
```
## Auth Setup
```bash
uxc auth credential set blocknative \
--auth-type api_key \
--api-key-header Authorization \
--secret-env BLOCKNATIVE_API_KEY
uxc auth binding add \
--id blocknative \
--host api.blocknative.com \
--scheme https \
--credential blocknative \
--priority 100
```
Validate the binding:
```bash
uxc auth binding match https://api.blocknative.com
```
## Read Examples
```bash
# Discover supported chains and their feature flags
blocknative-openapi-cli get:/chains
# Read gas price confidence intervals for Ethereum mainnet
blocknative-openapi-cli get:/gasprices/blockprices \
chainid=1 \
confidenceLevels=70,90,99
# Read gas prices by system + network instead of chainid
blocknative-openapi-cli get:/gasprices/blockprices \
system=story \
network=mainnet
# Read Ethereum base fee and blob fee predictions
blocknative-openapi-cli get:/gasprices/basefee-estimates
# Read current pending gas distribution for Ethereum mainnet
blocknative-openapi-cli get:/gasprices/distribution \
chainid=1
```
## Error Handling Pattern
```bash
# Keep error inspection at the UXC envelope level before debugging provider-specific fields
blocknative-openapi-cli get:/gasprices/basefee-estimates | jq '{ok, error, data}'
# If auth is missing or invalid, inspect .error first before assuming the endpoint is unavailable
blocknative-openapi-cli get:/gasprices/distribution chainid=1 | jq '.error'
```
## Fallback Equivalence
- `blocknative-openapi-cli <operation> ...` is equivalent to
`uxc https://api.blocknative.com --schema-url <blocknative_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/blocknative-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/blocknative-gas.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["/chains"] and .paths["/gasprices/blockprices"] and .paths["/gasprices/basefee-estimates"]' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'OpenAPI schema missing expected Blocknative paths'
jq -e '.paths["/gasprices/distribution"].get and .paths["/gasprices/blockprices"].get' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'OpenAPI schema must expose expected GET operations'
rg -q '^name:\s*blocknative-openapi-skill\s*$' "SKILL_FILE" || fail 'invalid skill name'
rg -q '^description:\s*.+' "SKILL_FILE" || fail 'missing description'
rg -q 'command -v blocknative-openapi-cli' "SKILL_FILE" || fail 'missing link-first command check'
rg -q 'uxc link blocknative-openapi-cli https://api.blocknative.com --schema-url ' "SKILL_FILE" || fail 'missing fixed link create command with schema-url'
rg -F -q 'blocknative-openapi-cli get:/gasprices/basefee-estimates -h' "SKILL_FILE" || fail 'missing operation-level help example'
rg -q -- '--api-key-header Authorization' "SKILL_FILE" || fail 'missing api key setup'
rg -q 'uxc auth binding match https://api.blocknative.com' "SKILL_FILE" || fail 'missing binding match check'
rg -q 'once per second' "SKILL_FILE" || fail 'missing polling 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*"Blocknative Gas Platform"\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*".*\$blocknative-openapi-skill.*"\s*$' "OPENAI_FILE" || fail 'default_prompt must mention $blocknative-openapi-skill'
echo "skills/blocknative-openapi-skill validation passed"
Connect a website to the local-mcp browser bridge through a fixed UXC link. Use when the user needs to operate native WebMCP sites or adapter-backed sites th...
---
name: webmcp-bridge
description: Connect a website to the local-mcp browser bridge through a fixed UXC link. Use when the user needs to operate native WebMCP sites or adapter-backed sites through local-mcp, manage per-site browser profiles, or switch bridge presentation modes explicitly.
---
# WebMCP Bridge
Use this skill to operate `@webmcp-bridge/local-mcp` through one fixed `uxc` shortcut command per site.
If the target site does not expose native WebMCP and does not already have a fallback adapter, switch to `$webmcp-adapter-creator`.
## Prerequisites
- `uxc` is installed and available in `PATH`.
- `npx` is installed and available in `PATH`.
- Network access is available for the target website.
- On a fresh machine, or under an isolated `HOME`, install Playwright browsers first with `npx playwright install`.
- For local repo development, you may replace the default `npx -y @webmcp-bridge/local-mcp` launcher with `WEBMCP_LOCAL_MCP_COMMAND='node packages/local-mcp/dist/cli.js'`.
## Core Workflow
1. Identify the bridge source mode before creating any link:
- Native or polyfill target: use `--url <url>`.
- Built-in adapter preset: use `--site <site>`.
- Third-party adapter module: use `--adapter-module <specifier>` and optionally `--url <url>`.
2. Pick one stable site name and one site-scoped profile path:
- default profile root: `~/.uxc/webmcp-profile/<site>`
- never share one profile across different sites
3. Create or refresh the fixed link for that site:
- `command -v <site>-webmcp-cli`
- if the link is missing or the source config changed, run `skills/webmcp-bridge/scripts/ensure-links.sh`
4. Inspect the bridge and tool schema before calling tools:
- `<site>-webmcp-cli -h`
- `<site>-webmcp-cli <operation> -h`
- `<site>-webmcp-cli <operation> field=value`
- `<site>-webmcp-cli <operation> '{"field":"value"}'`
5. Treat presentation mode as explicit runtime state, not command-name intent:
- check current state with `<site>-webmcp-cli bridge.session.status`
- or `<site>-webmcp-cli bridge.session.mode.get`
- `--headless` or `--no-headless` only sets the preferred default for bridge-managed sessions
- the actual runtime mode is `presentationMode`
6. Switch modes explicitly when needed:
- for normal automation, stay in `headless`
- for login, MFA, or human collaboration, run `<site>-webmcp-cli bridge.session.mode.set '{"mode":"headed"}'`
- then open or focus the visible session with `<site>-webmcp-cli bridge.open`
- if the user manually closes that window, the headed owner session ends; run `bridge.open` again to start a new headed session on the same profile
- close the visible owner session with `<site>-webmcp-cli bridge.close`
7. Parse JSON output only:
- success path: `.ok == true`, consume `.data`
- failure path: `.ok == false`, inspect `.error.code` and `.error.message`
## When Only Bridge Tools Are Visible
If `<site>-webmcp-cli -h` only shows `bridge.*` tools, do not keep retrying site tools blindly. The bridge is alive, but the page runtime is not attached to site tools yet.
Use this recovery order:
1. Inspect session state first:
- `<site>-webmcp-cli bridge.session.status`
2. If the session is bootstrap-only or auth is incomplete:
- run `<site>-webmcp-cli bridge.session.bootstrap`
- complete login in the browser window
- then re-run `<site>-webmcp-cli -h`
3. If a browser/profile already exists but the session is not attached to page tools:
- run `<site>-webmcp-cli bridge.session.attach`
- then re-run `<site>-webmcp-cli -h`
4. If the task needs a visible browser:
- run `<site>-webmcp-cli bridge.session.mode.set '{"mode":"headed"}'`
- run `<site>-webmcp-cli bridge.open`
5. Only call site operations after help output shows site tools again.
For auth-sensitive adapter sites such as `x` and `google`, seeing only bridge tools during first use is expected until bootstrap or attach completes successfully.
## Link Contract
Every site gets one fixed command:
- `<site>-webmcp-cli`
The link must keep one stable site profile and daemon lock:
- profile path: `~/.uxc/webmcp-profile/<site>`
- daemon key: same as profile path
The generated command should default to:
- use `--headless`
- use `--no-auto-login-fallback`
This keeps automation deterministic while still allowing runtime switching through:
- `bridge.session.mode.get`
- `bridge.session.mode.set`
- `bridge.open`
- `bridge.close`
Do not treat one command invocation as a guarantee that the current runtime has already switched. Always inspect `presentationMode` when mode matters.
## Guardrails
- Prefer browser-side execution for privileged site actions. Do not move site credentials into local scripts.
- Do not share one `--user-data-dir` across multiple unrelated sites.
- Do not dynamically rename link commands at runtime. The skill author chooses the link name once.
- For managed sessions, use `bridge.session.mode.set` instead of relying on a new launcher invocation to force a mode change.
- For external attach sessions, `bridge.session.mode.set` is unavailable. Attach to a headed external browser if the task needs a visible window.
- During `bootstrap_then_attach`, bootstrap is always `headed`. Do not try to switch mode until attach completes.
- `bridge.open` and `bridge.window.open` return `UNSUPPORTED_IN_HEADLESS_SESSION` when the current runtime is `headless`.
- For destructive writes, inspect tool help first and require explicit user intent.
- Use `--url` only for the site the user asked for. Do not silently redirect hosts.
## References
- Common creation and invocation patterns:
- `references/usage-patterns.md`
- Source mode selection and argument mapping:
- `references/source-modes.md`
- Link patterns, naming, and profile layout:
- `references/link-patterns.md`
- Common failures and recovery steps:
- `references/troubleshooting.md`
- Concrete creation script:
- `scripts/ensure-links.sh`
FILE:agents/openai.yaml
interface:
display_name: "WebMCP Bridge"
short_description: "Connect browser WebMCP sites through local-mcp"
default_prompt: "Use $webmcp-bridge to create or refresh local-mcp bridge links for a website and then call its tools through UXC."
policy:
allow_implicit_invocation: true
FILE:references/link-patterns.md
# Link Patterns
Use a fixed naming scheme so humans and agents can predict the command names.
## Link Names
For site name `<site>`:
- Link: `<site>-webmcp-cli`
Examples:
- `board-webmcp-cli`
- `x-webmcp-cli`
## Profile Layout
Use one profile directory per site:
```bash
~/.uxc/webmcp-profile/<site>
```
Examples:
```bash
~/.uxc/webmcp-profile/board
~/.uxc/webmcp-profile/x
```
For auth-sensitive sites such as `x` and `google`, the shared profile is also the anchor for
`bridge.session.bootstrap` and later attach-mode reuse. Do not omit `--user-data-dir` for those sites.
## Link Creation Pattern
```bash
command -v <site>-webmcp-cli
skills/webmcp-bridge/scripts/ensure-links.sh --name <site> --url <url>
<site>-webmcp-cli -h
<site>-webmcp-cli <operation> -h
```
## Invocation Pattern
Prefer `key=value` for simple inputs:
```bash
<site>-webmcp-cli <operation> field=value
```
For nested payloads, use one positional JSON object:
```bash
<site>-webmcp-cli <operation> '{"field":"value"}'
```
When mode matters, inspect and switch it explicitly:
```bash
<site>-webmcp-cli bridge.session.mode.get
<site>-webmcp-cli bridge.session.mode.set '{"mode":"headed"}'
<site>-webmcp-cli bridge.open
```
FILE:references/source-modes.md
# Source Modes
Pick exactly one primary source mode for each site link.
## URL mode
Use URL mode when the page itself exposes native WebMCP or when you want polyfill-only behavior without an adapter preset.
Examples:
```bash
skills/webmcp-bridge/scripts/ensure-links.sh --name board --url https://board.holon.run
skills/webmcp-bridge/scripts/ensure-links.sh --name board --url http://127.0.0.1:4173
```
Generated local-mcp arguments:
```bash
--url <url>
```
## Built-in adapter mode
Use a built-in site preset when `@webmcp-bridge/local-mcp` already ships the fallback adapter.
Example:
```bash
skills/webmcp-bridge/scripts/ensure-links.sh --name x --site x
```
Generated local-mcp arguments:
```bash
--site <site>
```
## External adapter mode
Use an external adapter module when the fallback implementation is shipped outside the local-mcp package.
Example:
```bash
skills/webmcp-bridge/scripts/ensure-links.sh \
--name fixture-demo \
--adapter-module ./examples/adapter-template/dist/index.js
```
Optional URL override example:
```bash
skills/webmcp-bridge/scripts/ensure-links.sh \
--name custom-site \
--adapter-module @your-scope/webmcp-adapter \
--url https://example.com
```
Generated local-mcp arguments:
```bash
--adapter-module <specifier> [--url <url>]
```
## Selection Rules
- If the user gives an exact URL and does not ask for a fallback adapter, start with URL mode.
- If the user asks for a built-in site preset such as `x`, use `--site`.
- If the user provides an npm package, file path, or `file://` URL for an adapter, use `--adapter-module`.
- Do not combine `--site` and `--adapter-module`.
FILE:references/troubleshooting.md
# Troubleshooting
## Link exists but points to old config
Recreate the link with `--force` through the helper script:
```bash
skills/webmcp-bridge/scripts/ensure-links.sh --name <site> ...
```
The script always refreshes the fixed site link.
## Headless flow cannot authenticate
Switch the managed session to `headed`, then open the visible window:
```bash
<site>-webmcp-cli bridge.session.mode.set '{"mode":"headed"}'
<site>-webmcp-cli bridge.open
```
After login, switch back explicitly if needed:
```bash
<site>-webmcp-cli bridge.session.mode.set '{"mode":"headless"}'
```
If `bridge.session.mode.set` returns `UNSUPPORTED_SESSION_CONTROL`, the current session is either external attach or bootstrap-only. Use a headed external browser, or finish attach first.
## Only bridge tools are visible
If `<site>-webmcp-cli -h` only lists `bridge.*`, the stdio bridge is running but the site runtime is not ready yet.
Start with:
```bash
<site>-webmcp-cli bridge.session.status
```
Then choose the next step from the status:
- If auth/bootstrap is incomplete, start or resume bootstrap:
```bash
<site>-webmcp-cli bridge.session.bootstrap
```
Complete login, then rerun:
```bash
<site>-webmcp-cli -h
```
- If the managed profile should already be logged in, attach the session:
```bash
<site>-webmcp-cli bridge.session.attach
```
Then rerun:
```bash
<site>-webmcp-cli -h
```
- If the task requires a visible browser while recovering:
```bash
<site>-webmcp-cli bridge.session.mode.set '{"mode":"headed"}'
<site>-webmcp-cli bridge.open
```
Only continue to business tools after help output shows the site operations again.
## The command default says headless but the session is still headed
The launcher only sets the preferred default for bridge-managed sessions. It does not force the current live session to restart.
Check actual runtime state:
```bash
<site>-webmcp-cli bridge.session.status
```
If the current session is managed, switch it explicitly:
```bash
<site>-webmcp-cli bridge.session.mode.set '{"mode":"headless"}'
```
## UI window flashes open and closes immediately
If the window still flashes open and disappears, verify that:
- `uxc` is updated to a recent release
- the `<site>-webmcp-cli` link was recreated after updating `uxc`
- the environment can launch Playwright browsers for the current `HOME`
- `bridge.session.status` reports `presentationMode = headed`
- the current daemon idle TTL policy is not immediately reaping the process after the command returns
Then rerun:
```bash
<site>-webmcp-cli bridge.open
```
If your environment needs a more aggressive keepalive policy for interactive sessions, recreate the link with an explicit daemon TTL override:
```bash
WEBMCP_DAEMON_IDLE_TTL=0 skills/webmcp-bridge/scripts/ensure-links.sh --name <site> ...
```
## The user closed the headed browser window manually
Run the same open command again:
```bash
<site>-webmcp-cli bridge.open
```
Closing the last headed browser window ends that owner session. The next `bridge.open` starts a new headed session on the same profile, without requiring a daemon reset.
## Fresh machine or isolated HOME cannot start Chromium
If `local-mcp` fails with an error that the Playwright browser executable does not exist, the current environment does not have Playwright browsers installed yet.
Install them once in that environment:
```bash
npx playwright install
```
This most commonly happens when:
- the machine is new
- the process is running under a temporary or isolated `HOME`
- browser caches were manually removed
## Multiple sites interfere with each other
This usually means the same profile directory was reused across sites. Move back to one profile per site:
```bash
~/.uxc/webmcp-profile/<site>
```
## A tool is missing after page navigation
Re-run tool help after the page stabilizes:
```bash
<site>-webmcp-cli -h
<site>-webmcp-cli <operation> -h
```
If the page changed meaningfully, refresh the bridge session by invoking the link again.
FILE:references/usage-patterns.md
# Usage Patterns
## URL-backed native site
```bash
command -v board-webmcp-cli
skills/webmcp-bridge/scripts/ensure-links.sh --name board --url https://board.holon.run
board-webmcp-cli -h
board-webmcp-cli nodes.list
```
## Built-in adapter site
```bash
command -v x-webmcp-cli
skills/webmcp-bridge/scripts/ensure-links.sh --name x --site x
x-webmcp-cli bridge.session.status
x-webmcp-cli bridge.session.bootstrap
x-webmcp-cli -h
x-webmcp-cli timeline.home.list -h
```
For auth-sensitive built-in sites such as `x`, expect the first headed run to require manual
sign-in against the managed profile before page tools become available.
## Third-party adapter module
```bash
skills/webmcp-bridge/scripts/ensure-links.sh \
--name custom-site \
--adapter-module @your-scope/webmcp-adapter \
--url https://example.com
custom-site-webmcp-cli -h
```
## JSON payload pattern
```bash
<site>-webmcp-cli <operation> field=value
<site>-webmcp-cli <operation> '{"field":"value"}'
```
## Mode switch pattern
```bash
<site>-webmcp-cli bridge.session.mode.get
<site>-webmcp-cli bridge.session.mode.set '{"mode":"headed"}'
<site>-webmcp-cli bridge.open
<site>-webmcp-cli <operation>
<site>-webmcp-cli bridge.close
```
FILE:scripts/ensure-links.sh
#!/usr/bin/env bash
set -euo pipefail
fail() {
printf '[webmcp-bridge] error: %s\n' "$*" >&2
exit 1
}
need_cmd() {
command -v "$1" >/dev/null 2>&1 || fail "required command not found: $1"
}
shell_join() {
local out=""
local arg
for arg in "$@"; do
if [[ -n "$out" ]]; then
out+=" "
fi
printf -v out '%s%q' "$out" "$arg"
done
printf '%s\n' "$out"
}
remove_file_if_exists() {
local path="$1"
if [[ -n "$path" && ( -e "$path" || -L "$path" ) && -L "$path" ]]; then
rm -f "$path"
fi
}
need_cmd uxc
need_cmd npx
name=""
url=""
site=""
adapter_module=""
profile=""
browser=""
link_dir=""
local_mcp_command="-npx -y @webmcp-bridge/local-mcp"
daemon_idle_ttl="-"
while [[ $# -gt 0 ]]; do
case "$1" in
--name)
[[ $# -ge 2 ]] || fail 'missing value for --name'
name="$2"
shift 2
;;
--url)
[[ $# -ge 2 ]] || fail 'missing value for --url'
url="$2"
shift 2
;;
--site)
[[ $# -ge 2 ]] || fail 'missing value for --site'
site="$2"
shift 2
;;
--adapter-module)
[[ $# -ge 2 ]] || fail 'missing value for --adapter-module'
adapter_module="$2"
shift 2
;;
--profile)
[[ $# -ge 2 ]] || fail 'missing value for --profile'
profile="$2"
shift 2
;;
--browser)
[[ $# -ge 2 ]] || fail 'missing value for --browser'
browser="$2"
shift 2
;;
--dir)
[[ $# -ge 2 ]] || fail 'missing value for --dir'
link_dir="$2"
shift 2
;;
--local-mcp-command)
[[ $# -ge 2 ]] || fail 'missing value for --local-mcp-command'
local_mcp_command="$2"
shift 2
;;
*)
fail "unknown argument: $1"
;;
esac
done
[[ -n "$name" ]] || fail 'missing required --name'
[[ "$name" =~ ^[a-z0-9][a-z0-9-]*$ ]] || fail 'name must match ^[a-z0-9][a-z0-9-]*$'
if [[ -n "$site" && -n "$adapter_module" ]]; then
fail 'use either --site or --adapter-module, not both'
fi
if [[ -z "$site" && -z "$adapter_module" && -z "$url" ]]; then
fail 'missing source: provide --url or one of --site/--adapter-module'
fi
if [[ -z "$profile" ]]; then
profile="$HOME/.uxc/webmcp-profile/$name"
fi
mkdir -p "$profile"
source_args=()
if [[ -n "$site" ]]; then
source_args+=(--site "$site")
fi
if [[ -n "$adapter_module" ]]; then
source_args+=(--adapter-module "$adapter_module")
fi
if [[ -n "$url" ]]; then
source_args+=(--url "$url")
fi
if [[ -n "$browser" ]]; then
source_args+=(--browser "$browser")
fi
link_name="name-webmcp-cli"
legacy_ui_link_name="name-webmcp-ui"
link_command=(uxc link)
if [[ -n "$link_dir" ]]; then
mkdir -p "$link_dir"
link_command+=(--dir "$link_dir")
fi
read -r -a launcher_parts <<< "$local_mcp_command"
link_args=("launcher_parts[@]" "source_args[@]" --headless --no-auto-login-fallback --user-data-dir "$profile")
link_value="$(shell_join "link_args[@]")"
link_install_args=("$link_name" "$link_value" --daemon-exclusive "$profile")
if [[ -n "$daemon_idle_ttl" ]]; then
link_install_args+=(--daemon-idle-ttl "$daemon_idle_ttl")
fi
link_install_args+=(--force)
"link_command[@]" "link_install_args[@]" >/dev/null
if [[ -n "$link_dir" ]]; then
remove_file_if_exists "$link_dir/$legacy_ui_link_name"
else
remove_file_if_exists "$HOME/.local/bin/$legacy_ui_link_name"
fi
printf 'linked %s -> %s\n' "$link_name" "$link_value"
printf 'profile %s\n' "$profile"
FILE:scripts/validate.sh
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "BASH_SOURCE[0]")/../../.." && pwd)"
SKILL_DIR="ROOT_DIR/skills/webmcp-bridge"
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
for f in \
"$SKILL_FILE" \
"$OPENAI_FILE" \
"SKILL_DIR/references/usage-patterns.md" \
"SKILL_DIR/references/source-modes.md" \
"SKILL_DIR/references/link-patterns.md" \
"SKILL_DIR/references/troubleshooting.md" \
"SKILL_DIR/scripts/ensure-links.sh"; do
[[ -f "$f" ]] || fail "missing required file: $f"
done
rg -q '^name:\s*webmcp-bridge\s*$' "$SKILL_FILE" || fail 'invalid skill name'
rg -q '^description:\s*.+' "$SKILL_FILE" || fail 'missing description'
rg -q 'command -v <site>-webmcp-cli' "$SKILL_FILE" || fail 'missing link-first check'
rg -q '<site>-webmcp-cli -h' "$SKILL_FILE" || fail 'missing help-first usage'
rg -q '<site>-webmcp-cli <operation> -h' "$SKILL_FILE" || fail 'missing operation help example'
rg -q '<site>-webmcp-cli <operation> field=value' "$SKILL_FILE" || fail 'missing key=value example'
rg -q "<site>-webmcp-cli <operation> '\{" "$SKILL_FILE" || fail 'missing positional JSON example'
rg -q 'bridge.session.mode.set' "$SKILL_FILE" || fail 'missing explicit mode switch guidance'
rg -q '~/.uxc/webmcp-profile/<site>' "$SKILL_FILE" || fail 'missing profile convention'
if rg -q -- '^[[:space:]]*(list|describe|call)([[:space:]]|$)|--input-json|--args[[:space:]]+\S' "$SKILL_FILE" "SKILL_DIR/references"; then
fail 'found banned legacy invocation patterns'
fi
echo 'skills/webmcp-bridge validation passed'
Create fallback site adapters for websites that do not expose native WebMCP. Use when a site needs a new adapter module, tool schema design, browser-side req...
---
name: webmcp-adapter-creator
description: Create fallback site adapters for websites that do not expose native WebMCP. Use when a site needs a new adapter module, tool schema design, browser-side request execution, or request-template extraction from observed page behavior.
---
# WebMCP Adapter Creator
Use this skill to create or update a fallback `SiteAdapter` for `@webmcp-bridge/local-mcp`.
## When To Use
Use this skill when:
- the target site does not expose native `navigator.modelContext`
- an existing adapter does not exist yet
- an existing adapter needs new tools, pagination, or request-template refresh
- a site requires browser-side request execution instead of DOM-only scraping
If the user only needs to connect to an existing site through the bridge, use `$webmcp-bridge` instead.
## Prerequisites
- The target site URL is known.
- The user can authenticate in the browser profile if the site requires login.
- `pnpm` is installed for local package work.
- `npx playwright install` has already been run in the current environment when Playwright browsers are not present.
## Core Workflow
1. Confirm the site really needs a fallback adapter:
- check whether native `navigator.modelContext` already exists
- if native WebMCP exists, stop and use `$webmcp-bridge` instead of writing an adapter
2. Scaffold a new adapter package when starting from scratch:
- `skills/webmcp-adapter-creator/scripts/scaffold-adapter.sh --name <site> --host <host> --url <url>`
3. Fix the contract first:
- implement `manifest`
- implement `createAdapter()`
- keep all payloads JSON-serializable
4. Design the tool surface before coding extraction logic:
- use stable product names such as `tweet.get`, `timeline.home.list`, `user.get`
- put parameter details in schema field descriptions, not only in tool descriptions
5. Prefer browser-side request execution over server-side credential replay:
- run requests in the page context so the site's own auth/session state is reused
- do not move cookies or bearer tokens into local-mcp
6. Discover stable request templates from real page behavior:
- trigger the target action in the page
- observe the network request shape
- extract a reusable request template with placeholders for ids, cursors, queries, or feature flags
7. Implement fallback layers explicitly:
- first try browser-side network/template execution
- for assistant/chat products, prefer intercepting the product's real request/response path over reading rendered text
- if network execution is unavailable or the template is missing, fall back to DOM extraction when safe
- include `source` and `reason` fields so callers can see which path ran
- when a helper is cross-site and not product-specific, prefer putting it in a shared adapter utility package instead of copying it into one adapter
- for long prompts, prefer one-shot DOM insertion into the real composer and use incremental `type()` or `fill()` only as a fallback
- when waiting for chat/image completion, use activity-aware idle deadlines instead of a fixed wall-clock timeout
- activity signals may include stop controls, response fingerprint changes, feedback buttons, or generated image count changes
- compare against a normalized snapshot of the previous response before declaring a new answer ready
- do not reset or reopen the page during fallback confirmation if that would lose the current conversation/session context
8. Add contract and integration coverage:
- package-local unit tests for tool behavior and validation
- local-mcp integration tests for full bridge execution
- cover long prompt insertion, long-thinking waits, stale-response misdetection, and session-preserving fallback paths
## Guardrails
- Keep site logic inside the adapter package only.
- Fail closed on ambiguous upstream states such as `AUTH_REQUIRED`, `UPSTREAM_CHANGED`, and `CHALLENGE_REQUIRED`.
- Prefer stable request templates over brittle DOM-only scraping for authenticated data reads.
- Do not add credential vaulting, secret replay, or auth bypass logic.
- The browser page is the execution environment for privileged site actions.
## References
- End-to-end adapter creation flow:
- `references/workflow.md`
- How to discover requests from page behavior:
- `references/network-discovery.md`
- How to turn captured requests into reusable templates:
- `references/request-template-patterns.md`
- Runtime patterns for streamed responses, request interception, and session-aware tools:
- `references/adapter-runtime-patterns.md`
- Testing expectations for adapter packages:
- `references/testing.md`
- Adapter scaffold helper:
- `scripts/scaffold-adapter.sh`
FILE:agents/openai.yaml
interface:
display_name: "WebMCP Adapter Creator"
short_description: "Create fallback adapters for non-WebMCP sites"
default_prompt: "Use $webmcp-adapter-creator to scaffold a new site adapter, discover browser-side requests, and design stable tool contracts for local-mcp fallback mode."
policy:
allow_implicit_invocation: true
FILE:references/adapter-runtime-patterns.md
# Adapter Runtime Patterns
These patterns come from real adapter work where a site's UI was not stable enough to support a DOM-first implementation.
Use them when a fallback adapter needs authenticated reads or writes that are driven by browser-side requests.
## 1. Prefer Real Request Interception Over Reconstructed Fetch
If the page already knows how to make the request, intercept that real request before trying to reconstruct it yourself.
Why:
- manually replaying auth-heavy requests often fails even when URL and body look correct
- dynamic headers, transaction ids, and internal conversation state are easy to miss
- the page's own request shape is usually the most reliable source of truth
Recommended order:
1. intercept the real browser request
2. inspect whether the intercepted response already contains the data you need
3. only fall back to manual in-page replay if interception cannot expose the response body
## 2. `route.fetch()` Is Better Than DOM Guessing For Streamed Responses
For some sites, the request is normal HTTP but the response is streamed or chunked.
In this case:
- CDP `getResponseBody` may return nothing useful
- DOM extraction often captures intermediate UI text instead of the final answer
- `page.route(..., route => route.fetch())` can still read the real response text
Recommended pattern:
1. intercept the real request with `page.route`
2. skip preflight `OPTIONS`
3. call `route.fetch()`
4. read the response text
5. parse the stream format
6. `route.fulfill({ response })` so the page still behaves normally
This lets the adapter observe the site's real response while preserving the page's normal execution path.
## 3. Treat Sessions As First-Class Tool Inputs
If the upstream product has a session or conversation concept, the adapter should expose it explicitly.
Do not rely on "whatever page is currently open" as the conversation source.
Recommended tool contract:
- default behavior creates a new session
- optional `conversationId` continues an existing session
- return `conversationId` in successful results
This makes agent behavior reproducible and avoids hidden context leaks between calls.
## 4. New Session Must Be Explicit, Not Implicit
If the tool should start a fresh session when no session id is supplied, make that an explicit browser action.
Example pattern:
1. open the product landing route
2. detect the current session id from the URL or page state
3. click `New Chat` or equivalent
4. wait until the previous session id disappears or changes
5. only then send the new request
Do not assume that navigating to the same route automatically starts a new session.
## 5. Parse The Protocol, Not The Rendered Text
For assistant-like products, the DOM often exposes:
- thinking text
- partial tokens
- button labels
- suggestion chips
- replay artifacts
If the response stream contains structured events, parse those instead of reading visible text.
Look for fields such as:
- event type
- message tag
- final chunk markers
- conversation/session ids
Then build the final answer from the protocol itself.
## 6. Keep DOM As Fallback Only
DOM extraction is still useful, but only as a last resort.
Use DOM fallback when:
- the request cannot be intercepted
- the response body is unavailable
- the upstream site changed and the request path is temporarily broken
When falling back:
- return a clear reason internally or in debug output
- keep DOM parsing narrow and conservative
- prefer fail-closed over silently returning noisy text
## 7. Validate Runtime Assumptions With Minimal Probes
When adapter behavior is ambiguous, write a tiny probe before rewriting production code.
Good probe targets:
- can `route.fetch()` read the body?
- is the response streamed or plain JSON?
- does manual in-page replay return 404 or CORS failure?
- does the page use a new session by default or preserve the old one?
These probes help separate:
- a bad implementation idea
- a good idea with one missing runtime detail
## 8. Keep The Reusable Logic In Patterns, Not Site Constants
The reusable part is usually the execution pattern, not the exact endpoint name.
Examples of reusable adapter-library patterns:
- request interception wrappers
- streamed NDJSON parsing helpers
- session-aware tool input/output conventions
- "network first, DOM fallback" execution scaffolding
- explicit confirmation and fail-closed result mapping
Examples of site-specific details that should stay in the adapter:
- endpoint paths
- query ids
- request body fields
- URL shapes
- product button labels
When documenting or extracting shared helpers, keep this boundary explicit.
## 9. Prefer A Small Shared Utility Layer For Cross-Site Pieces
If several adapters need the same low-level mechanics, put them in a shared adapter utility package instead of copying them between site adapters.
Good candidates for that package:
- text normalization and dedupe helpers
- streamed NDJSON parsing helpers
- routed-response capture helpers around `page.route(...)/route.fetch()`
- request-template data structures and simple cache helpers
- generic request-capture script builders for page-side fetch/XHR recording
Keep these out of the shared package:
- site endpoint names
- query ids
- site-specific request matchers
- response parsers tied to one product
- button labels and DOM selectors with product semantics
Use the shared package for low-level mechanics, then keep matching, templating, and response interpretation inside the site adapter.
If you discover a reusable helper while building an adapter and it looks broadly useful, consider contributing it back to the `webmcp-bridge` repository as a focused PR.
FILE:references/network-discovery.md
# Network Discovery
Discover the site's real read or write interface by observing actual browser behavior.
## Goal
Capture the request that the page already knows how to make, then reuse that shape from the page context.
This is usually more stable than trying to reconstruct auth headers or cookies outside the browser.
## Discovery Procedure
1. Open the target page in a real logged-in browser session.
2. Trigger one concrete action that matches the tool you want.
3. Observe network traffic and identify the request that produced the result.
4. Record the stable parts:
- URL path
- method
- request body or query structure
- variables payload
- feature flags or toggles
- cursor location for pagination
5. Record the variable parts separately:
- item id
- user id or screen name
- query string
- cursor
- limit or count
6. Check whether the same request shape works across several examples.
## What To Look For
Look for a request shape that is:
- initiated by page code, not by a browser extension
- repeatable across multiple actions
- parameterized in obvious places
- valid inside `page.evaluate()` or in-page fetch
## Good Signals
Good candidates usually have:
- one stable endpoint path
- one stable request method
- a JSON variable payload that changes only in a few fields
- cursors embedded in response entries or metadata
## Bad Signals
Avoid anchoring the adapter on:
- volatile DOM class names alone
- one-off bootstrap responses that are not repeatable
- requests that only appear once during initial hydration and cannot be replayed in-page
- headers or tokens captured outside the browser and replayed from local-mcp
## Browser-Side Principle
The goal is not to emulate the site's auth model in Node.js.
The goal is to let the page execute the request while the browser session already holds the necessary auth state.
FILE:references/request-template-patterns.md
# Request Template Patterns
Turn one successful observed request into a reusable template.
## Template Shape
A practical template usually needs:
- `url`
- `method`
- a sanitized header subset when required by in-page fetch
- stable query parameters or body sections
- placeholders for variable fields
For pagination-capable reads, also define:
- where the incoming cursor goes
- where the next cursor is extracted from the response
## Extraction Strategy
1. Capture one successful request.
2. Remove values that should not be hard-coded forever.
3. Keep only the minimal stable request shape.
4. Replace changeable values with adapter-level variables.
Typical variable fields:
- `tweetId`
- `userId`
- `screenName`
- `query`
- `cursor`
- `count`
## Execution Pattern
Inside the adapter, execute the request from the page context:
- build the next request URL or body from the template
- inject variable fields
- call `fetch()` in the page context
- parse the JSON response
- extract `items` and optional `nextCursor`
## Fallback Pattern
When there is no captured template yet, or the request fails after an upstream site change:
- return `source: "dom"`
- include a concrete `reason`, such as `no_template` or `request_failed`
- fall back to DOM extraction only if the DOM path is still meaningful
## Cache Scope
Template caching should be explicit.
Reasonable cache scopes:
- page lifetime cache for one navigation session
- process-level cache for repeated reads in one bridge process
Refresh the template when:
- the page navigates to a materially different route
- the request starts failing in a way that suggests upstream changes
- response parsing no longer matches the previous shape
FILE:references/testing.md
# Testing
Adapters need both contract tests and full bridge tests.
## Contract Coverage
At the adapter package level, test:
- manifest validity
- tool list shape
- validation errors for malformed inputs
- stable success payload shape
- stable error payload shape
## Integration Coverage
At the bridge level, test:
- `tools/list` through `local-mcp`
- `tools/call` through `local-mcp`
- native-first fallback behavior when native WebMCP is absent
- adapter startup and teardown behavior when relevant
## Read Path Expectations
For paginated read tools, verify:
- first page without `cursor`
- follow-up page with `cursor`
- `items`, `hasMore`, and `nextCursor`
- `source` and `reason` when DOM fallback happens
## Real Site Safety
For real authenticated sites:
- prefer read-only smoke coverage in CI or local verification
- keep destructive writes behind explicit user intent
- do not hard-code secrets in tests
FILE:references/workflow.md
# Workflow
## 1. Check whether an adapter is needed
Before writing adapter code, verify whether the site already exposes native WebMCP.
If native WebMCP exists:
- stop adapter work
- use `$webmcp-bridge`
- create site wrapper skills only if they improve UX
If native WebMCP does not exist:
- continue with fallback adapter creation
## 2. Scaffold the package
Use the helper script to create a starting package from `examples/adapter-template`:
```bash
skills/webmcp-adapter-creator/scripts/scaffold-adapter.sh \
--name <site> \
--host <host> \
--url <url>
```
Default output path:
```bash
packages/adapter-<site>
```
## 3. Define the tool contract first
Start from user-facing capabilities, not implementation details.
Preferred naming examples:
- `tweet.get`
- `timeline.home.list`
- `timeline.user.list`
- `user.get`
- `favorites.list`
- `search.tweets.list`
For each tool:
- add a stable description
- add field-level schema descriptions
- keep inputs small and predictable
- use pagination shape consistently: `limit`, optional `cursor` -> `items`, `hasMore`, optional `nextCursor`
## 4. Implement browser-side execution
Adapters should use the Playwright page as the privileged runtime.
Preferred order:
1. page-context network/template execution
2. DOM fallback only when network/template execution is unavailable or insufficient
## 5. Add error mapping
Map raw failures into stable adapter errors:
- `AUTH_REQUIRED`
- `CHALLENGE_REQUIRED`
- `UPSTREAM_CHANGED`
- `VALIDATION_ERROR`
- `TOOL_NOT_FOUND`
## 6. Test the package
Minimum expectation:
- package `typecheck`
- package `build`
- local tool contract tests
- local-mcp integration path for the adapter source
FILE:scripts/scaffold-adapter.sh
#!/usr/bin/env bash
set -euo pipefail
fail() {
printf '[webmcp-adapter-creator] error: %s\n' "$*" >&2
exit 1
}
need_cmd() {
command -v "$1" >/dev/null 2>&1 || fail "required command not found: $1"
}
ROOT_DIR="$(cd "$(dirname "BASH_SOURCE[0]")/../../.." && pwd)"
TEMPLATE_DIR="ROOT_DIR/examples/adapter-template"
need_cmd cp
need_cmd mkdir
need_cmd perl
name=""
host=""
url=""
out_dir=""
display_name=""
package_name=""
while [[ $# -gt 0 ]]; do
case "$1" in
--name)
[[ $# -ge 2 ]] || fail 'missing value for --name'
name="$2"
shift 2
;;
--host)
[[ $# -ge 2 ]] || fail 'missing value for --host'
host="$2"
shift 2
;;
--url)
[[ $# -ge 2 ]] || fail 'missing value for --url'
url="$2"
shift 2
;;
--dir)
[[ $# -ge 2 ]] || fail 'missing value for --dir'
out_dir="$2"
shift 2
;;
--display-name)
[[ $# -ge 2 ]] || fail 'missing value for --display-name'
display_name="$2"
shift 2
;;
--package-name)
[[ $# -ge 2 ]] || fail 'missing value for --package-name'
package_name="$2"
shift 2
;;
*)
fail "unknown argument: $1"
;;
esac
done
[[ -n "$name" ]] || fail 'missing required --name'
[[ "$name" =~ ^[a-z0-9][a-z0-9-]*$ ]] || fail 'name must match ^[a-z0-9][a-z0-9-]*$'
[[ -n "$host" ]] || fail 'missing required --host'
[[ -n "$url" ]] || fail 'missing required --url'
if [[ -z "$out_dir" ]]; then
out_dir="ROOT_DIR/packages/adapter-name"
fi
if [[ -z "$display_name" ]]; then
display_name="$name"
fi
if [[ -z "$package_name" ]]; then
package_name="@webmcp-bridge/adapter-name"
fi
[[ ! -e "$out_dir" ]] || fail "output path already exists: $out_dir"
mkdir -p "$out_dir/src"
cp "TEMPLATE_DIR/package.json" "$out_dir/package.json"
cp "TEMPLATE_DIR/tsconfig.json" "$out_dir/tsconfig.json"
cp "TEMPLATE_DIR/src/index.ts" "$out_dir/src/index.ts"
LC_ALL=C perl -0pi -e "s#\Q@webmcp-bridge/example-adapter-template\E#package_name#g" "$out_dir/package.json"
LC_ALL=C perl -0pi -e "s#\Qadapter-template\E#adapter-name#g" "$out_dir/src/index.ts"
LC_ALL=C perl -0pi -e "s#\QAdapter Template\E#display_name#g" "$out_dir/src/index.ts"
LC_ALL=C perl -0pi -e "s#\Qexample.com\E#host#g" "$out_dir/src/index.ts"
LC_ALL=C perl -0pi -e "s#\Qhttps://example.com\E#url#g" "$out_dir/src/index.ts"
printf 'scaffolded %s\n' "$out_dir"
printf 'package %s\n' "$package_name"
printf 'next: edit %s/src/index.ts\n' "$out_dir"
FILE:scripts/validate.sh
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "BASH_SOURCE[0]")/../../.." && pwd)"
SKILL_DIR="ROOT_DIR/skills/webmcp-adapter-creator"
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
for f in \
"$SKILL_FILE" \
"$OPENAI_FILE" \
"SKILL_DIR/references/workflow.md" \
"SKILL_DIR/references/network-discovery.md" \
"SKILL_DIR/references/request-template-patterns.md" \
"SKILL_DIR/references/testing.md" \
"SKILL_DIR/scripts/scaffold-adapter.sh"; do
[[ -f "$f" ]] || fail "missing required file: $f"
done
rg -q '^name:\s*webmcp-adapter-creator\s*$' "$SKILL_FILE" || fail 'invalid skill name'
rg -q '^description:\s*.+' "$SKILL_FILE" || fail 'missing description'
rg -q 'scaffold-adapter.sh --name <site> --host <host> --url <url>' "$SKILL_FILE" || fail 'missing scaffold workflow'
rg -q 'browser-side request execution' "$SKILL_FILE" || fail 'missing browser-side execution guidance'
rg -q 'request-template' "$SKILL_FILE" || fail 'missing request-template guidance'
rg -q '\$webmcp-bridge' "$SKILL_FILE" || fail 'missing bridge handoff guidance'
rg -q 'Do not add credential vaulting, secret replay, or auth bypass logic\.' "$SKILL_FILE" || fail 'missing auth safety guardrail'
echo 'skills/webmcp-adapter-creator validation passed'
Connect to the native board demo through local-mcp and one fixed UXC link. Use when the user wants to inspect or edit the shared board at board.holon.run or...
---
name: board-webmcp
description: Connect to the native board demo through local-mcp and one fixed UXC link. Use when the user wants to inspect or edit the shared board at board.holon.run or a local board instance through browser WebMCP.
---
# Board WebMCP
Use this skill to operate the native board demo through `@webmcp-bridge/local-mcp`.
## Prerequisites
- `uxc` is installed and available in `PATH`.
- `npx` is installed and available in `PATH`.
- Network access to `https://board.holon.run`.
- On a fresh machine, or under an isolated `HOME`, install Playwright browsers first with `npx playwright install`.
- For local board development, point the setup script at `http://127.0.0.1:4173`.
## Core Workflow
1. Ensure the fixed board link exists:
- `command -v board-webmcp-cli`
- if missing or pointed at the wrong URL, run `skills/board-webmcp/scripts/ensure-links.sh`
2. Inspect the bridge and tool schema before calling tools:
- `board-webmcp-cli -h`
- `board-webmcp-cli nodes.list -h`
- `board-webmcp-cli nodes.upsert -h`
3. Read current board state:
- non-collaborative automation: `board-webmcp-cli nodes.list`, `board-webmcp-cli edges.list`
- collaborative visible session:
- `board-webmcp-cli bridge.session.mode.set '{"mode":"headed"}'`
- `board-webmcp-cli bridge.open`
- `board-webmcp-cli nodes.list`
- `board-webmcp-cli edges.list`
4. Apply updates with structured inputs:
- `board-webmcp-cli diagram.export format=json`
- collaborative visible session should keep the same runtime in `headed`
- `board-webmcp-cli nodes.upsert '{"nodes":[{"label":"Fraud Service","kind":"service"}]}'`
- `board-webmcp-cli edges.upsert '{"edges":[{"sourceNodeId":"gateway","targetNodeId":"orders","protocol":"grpc"}]}'`
- `board-webmcp-cli layout.apply mode=layered`
- `board-webmcp-cli diagram.export format=json`
5. When a human is editing or reviewing the same board live:
- check current state with `board-webmcp-cli bridge.session.status`
- if needed, switch to headed with `board-webmcp-cli bridge.session.mode.set '{"mode":"headed"}'`
- `board-webmcp-cli bridge.open`
- keep all reads and writes on `board-webmcp-cli` for that same collaborative session
- `board-webmcp-cli selection.get`
- `board-webmcp-cli bridge.close`
- if the human closed the board window manually, the headed owner session has ended; run `board-webmcp-cli bridge.open` again to start a new headed session on the same profile
## Default Target
The default public target is:
```bash
https://board.holon.run
```
The default board profile path is:
```bash
~/.uxc/webmcp-profile/board
```
Use the helper script to refresh the link for the public deployment:
```bash
skills/board-webmcp/scripts/ensure-links.sh
```
Use the helper script to point the link at local development instead:
```bash
skills/board-webmcp/scripts/ensure-links.sh --url http://127.0.0.1:4173
```
If the bridge fails to start on a fresh machine or inside an isolated `HOME`, install Playwright browsers in that environment first:
```bash
npx playwright install
```
## Guardrails
- `board.holon.run` is a shared demo. Writes are visible on the board surface and persisted in browser storage for that profile.
- Prefer explicit `bridge.session.mode.set` over relying on a new launcher invocation to change runtime mode.
- Before collaborative editing, confirm the runtime is actually `headed`.
- If the human closes that window manually, the headed owner session ends. The next `board-webmcp-cli bridge.open` starts a new headed session on the same profile.
- Keep the board profile isolated from other sites.
- Use JSON output for automation. Do not depend on human-formatted text output.
## References
- Common command patterns:
- `references/usage-patterns.md`
- Link creation helper:
- `scripts/ensure-links.sh`
FILE:agents/openai.yaml
interface:
display_name: "Board WebMCP"
short_description: "Operate the board demo through local-mcp"
default_prompt: "Use $board-webmcp to connect to board.holon.run, inspect the board schema, and update the shared diagram through local-mcp."
policy:
allow_implicit_invocation: true
FILE:references/usage-patterns.md
# Usage Patterns
## Create or refresh links
```bash
command -v board-webmcp-cli
skills/board-webmcp/scripts/ensure-links.sh
board-webmcp-cli -h
```
## Read path
```bash
board-webmcp-cli nodes.list
board-webmcp-cli edges.list
```
For a human + AI collaborative session on the same visible board, switch the runtime first:
```bash
board-webmcp-cli bridge.session.mode.get
board-webmcp-cli bridge.session.mode.set '{"mode":"headed"}'
board-webmcp-cli bridge.open
board-webmcp-cli diagram.get
board-webmcp-cli nodes.list
board-webmcp-cli edges.list
```
Inspect a specific tool first when the payload matters:
```bash
board-webmcp-cli nodes.upsert -h
board-webmcp-cli edges.upsert -h
board-webmcp-cli layout.apply -h
```
## Write path
Create or update nodes:
```bash
board-webmcp-cli nodes.upsert '{"nodes":[{"label":"Fraud Service","kind":"service","x":1440,"y":120}]}'
```
Create or update edges:
```bash
board-webmcp-cli edges.upsert '{"edges":[{"sourceNodeId":"gateway","targetNodeId":"orders","protocol":"grpc"}]}'
```
Apply deterministic layout:
```bash
board-webmcp-cli layout.apply mode=grid
```
Export the document:
```bash
board-webmcp-cli diagram.export format=json
```
For a collaborative visible session, use the same operations after switching to `headed`:
```bash
board-webmcp-cli nodes.upsert '{"nodes":[{"label":"Fraud Service","kind":"service","x":1440,"y":120}]}'
board-webmcp-cli edges.upsert '{"edges":[{"sourceNodeId":"gateway","targetNodeId":"orders","protocol":"grpc"}]}'
board-webmcp-cli layout.apply mode=grid
board-webmcp-cli diagram.export format=json
```
## Local development target
```bash
skills/board-webmcp/scripts/ensure-links.sh --url http://127.0.0.1:4173
```
## UI collaboration session
```bash
board-webmcp-cli bridge.session.mode.set '{"mode":"headed"}'
board-webmcp-cli bridge.open
board-webmcp-cli selection.get
board-webmcp-cli bridge.close
```
FILE:scripts/ensure-links.sh
#!/usr/bin/env bash
set -euo pipefail
fail() {
printf '[board-webmcp] error: %s\n' "$*" >&2
exit 1
}
need_cmd() {
command -v "$1" >/dev/null 2>&1 || fail "required command not found: $1"
}
shell_join() {
local out=""
local arg
for arg in "$@"; do
if [[ -n "$out" ]]; then
out+=" "
fi
printf -v out '%s%q' "$out" "$arg"
done
printf '%s\n' "$out"
}
need_cmd uxc
need_cmd npx
url="https://board.holon.run"
profile="$HOME/.uxc/webmcp-profile/board"
link_dir=""
local_mcp_command="-npx -y @webmcp-bridge/local-mcp"
daemon_idle_ttl="-"
while [[ $# -gt 0 ]]; do
case "$1" in
--url)
[[ $# -ge 2 ]] || fail 'missing value for --url'
url="$2"
shift 2
;;
--profile)
[[ $# -ge 2 ]] || fail 'missing value for --profile'
profile="$2"
shift 2
;;
--dir)
[[ $# -ge 2 ]] || fail 'missing value for --dir'
link_dir="$2"
shift 2
;;
--local-mcp-command)
[[ $# -ge 2 ]] || fail 'missing value for --local-mcp-command'
local_mcp_command="$2"
shift 2
;;
*)
fail "unknown argument: $1"
;;
esac
done
mkdir -p "$profile"
link_command=(uxc link)
if [[ -n "$link_dir" ]]; then
mkdir -p "$link_dir"
link_command+=(--dir "$link_dir")
fi
read -r -a launcher_parts <<< "$local_mcp_command"
link_args=("launcher_parts[@]" --url "$url" --headless --no-auto-login-fallback --user-data-dir "$profile")
link_value="$(shell_join "link_args[@]")"
link_install_args=(board-webmcp-cli "$link_value" --daemon-exclusive "$profile")
if [[ -n "$daemon_idle_ttl" ]]; then
link_install_args+=(--daemon-idle-ttl "$daemon_idle_ttl")
fi
link_install_args+=(--force)
"link_command[@]" "link_install_args[@]" >/dev/null
printf 'linked %s -> %s\n' 'board-webmcp-cli' "$link_value"
printf 'profile %s\n' "$profile"
FILE:scripts/validate.sh
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "BASH_SOURCE[0]")/../../.." && pwd)"
SKILL_DIR="ROOT_DIR/skills/board-webmcp"
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
for f in \
"$SKILL_FILE" \
"$OPENAI_FILE" \
"SKILL_DIR/references/usage-patterns.md" \
"SKILL_DIR/scripts/ensure-links.sh"; do
[[ -f "$f" ]] || fail "missing required file: $f"
done
rg -q '^name:\s*board-webmcp\s*$' "$SKILL_FILE" || fail 'invalid skill name'
rg -q '^description:\s*.+' "$SKILL_FILE" || fail 'missing description'
rg -q 'command -v board-webmcp-cli' "$SKILL_FILE" || fail 'missing link-first check'
rg -q 'board-webmcp-cli -h' "$SKILL_FILE" || fail 'missing help-first usage'
rg -q 'board-webmcp-cli nodes.list -h' "$SKILL_FILE" || fail 'missing operation help example'
rg -q 'board-webmcp-cli nodes.upsert' "$SKILL_FILE" || fail 'missing write example'
rg -q 'board-webmcp-cli diagram.export format=json' "$SKILL_FILE" || fail 'missing key=value example'
rg -q 'bridge.session.mode.set' "$SKILL_FILE" || fail 'missing explicit mode switch guidance'
rg -q '~/.uxc/webmcp-profile/board' "$SKILL_FILE" || fail 'missing profile convention'
if rg -q -- '(^|[[:space:]])(list|describe|call)([[:space:]]|$)|--input-json|--args .*[{]' "$SKILL_FILE" "SKILL_DIR/references"; then
fail 'found banned legacy invocation patterns'
fi
echo 'skills/board-webmcp validation passed'
Operate WhatsApp Business Platform Cloud API through UXC with a curated OpenAPI schema, bearer-token auth, and message/profile guardrails.
---
name: whatsapp-openapi-skill
description: Operate WhatsApp Business Platform Cloud API through UXC with a curated OpenAPI schema, bearer-token auth, and message/profile guardrails.
---
# WhatsApp Cloud API Skill
Use this skill to run WhatsApp Business Platform Cloud 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://graph.facebook.com/v25.0`.
- Access to the curated OpenAPI schema URL:
- `https://raw.githubusercontent.com/holon-run/uxc/main/skills/whatsapp-openapi-skill/references/whatsapp-cloud.openapi.json`
- A Meta app and WhatsApp Business account with Cloud API access.
- A valid system-user or app access token that can call the target WhatsApp assets.
- At least one `phone_number_id`, and for phone number listing, the related `waba_id`.
## Scope
This skill covers a compact Cloud API request/response surface:
- phone number listing
- phone number metadata reads
- business profile reads and updates
- outbound message sends
This skill does **not** cover:
- inbound webhook receiver runtime
- template lifecycle management
- embedded signup or broader business onboarding flows
- media upload/download lifecycle
- the full WhatsApp Business Platform surface
## API Version
This skill is pinned to Graph API `v25.0`, based on current Meta developer examples at implementation time. Keep the base URL versioned:
- `https://graph.facebook.com/v25.0`
If Meta deprecates this version later, the wrapper should be revised in a follow-up update rather than assuming unversioned compatibility.
## Authentication
WhatsApp Cloud API uses `Authorization: Bearer <access_token>`.
Configure one bearer credential and bind it to the versioned Graph API base path:
```bash
uxc auth credential set whatsapp-cloud \
--auth-type bearer \
--secret-env WHATSAPP_CLOUD_ACCESS_TOKEN
uxc auth binding add \
--id whatsapp-cloud \
--host graph.facebook.com \
--path-prefix /v25.0 \
--scheme https \
--credential whatsapp-cloud \
--priority 100
```
Validate the active mapping when auth looks wrong:
```bash
uxc auth binding match https://graph.facebook.com/v25.0
```
## Core Workflow
1. Use the fixed link command by default:
- `command -v whatsapp-openapi-cli`
- If missing, create it:
`uxc link whatsapp-openapi-cli https://graph.facebook.com/v25.0 --schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/whatsapp-openapi-skill/references/whatsapp-cloud.openapi.json`
- `whatsapp-openapi-cli -h`
2. Inspect operation schema first:
- `whatsapp-openapi-cli get:/{waba_id}/phone_numbers -h`
- `whatsapp-openapi-cli get:/{phone_number_id}/whatsapp_business_profile -h`
- `whatsapp-openapi-cli post:/{phone_number_id}/messages -h`
3. Prefer read/setup validation before writes:
- `whatsapp-openapi-cli get:/{waba_id}/phone_numbers waba_id=123456789012345`
- `whatsapp-openapi-cli get:/{phone_number_id} phone_number_id=123456789012345`
- `whatsapp-openapi-cli get:/{phone_number_id}/whatsapp_business_profile phone_number_id=123456789012345`
4. Execute with key/value or positional JSON:
- key/value:
`whatsapp-openapi-cli get:/{phone_number_id} phone_number_id=123456789012345 fields=display_phone_number,verified_name`
- positional JSON:
`whatsapp-openapi-cli post:/{phone_number_id}/messages '{"phone_number_id":"123456789012345","messaging_product":"whatsapp","to":"15551234567","type":"text","text":{"body":"Hello from UXC"}}'`
## Operation Groups
### Asset Discovery
- `get:/{waba_id}/phone_numbers`
- `get:/{phone_number_id}`
### Business Profile
- `get:/{phone_number_id}/whatsapp_business_profile`
- `post:/{phone_number_id}/whatsapp_business_profile`
### Messaging
- `post:/{phone_number_id}/messages`
## Guardrails
- Keep automation on the JSON output envelope; do not use `--text`.
- Parse stable fields first: `ok`, `kind`, `protocol`, `data`, `error`.
- `post:/{phone_number_id}/messages` is a high-risk write. Require explicit user confirmation before execution.
- Message delivery is still constrained by WhatsApp conversation rules, template approval rules, recipient opt-in expectations, and account policy state. Auth success does not imply a send is allowed.
- This v1 skill does not manage media uploads. If you send `image` or `document` content, use already hosted URLs or existing asset references as allowed by the platform.
- Webhook subscription and verification are intentionally documented only. This skill does not configure a receiver runtime.
- Business profile update fields are partial. Only send the fields you intend to change.
- `whatsapp-openapi-cli <operation> ...` is equivalent to `uxc https://graph.facebook.com/v25.0 --schema-url <whatsapp_openapi_schema> <operation> ...`.
## References
- Usage patterns: `references/usage-patterns.md`
- Curated OpenAPI schema: `references/whatsapp-cloud.openapi.json`
- WhatsApp Cloud API docs: https://developers.facebook.com/docs/whatsapp/cloud-api
- Graph API access tokens: https://developers.facebook.com/docs/graph-api/overview/access-tokens/
FILE:agents/openai.yaml
interface:
display_name: "WhatsApp Cloud API"
short_description: "Operate WhatsApp Cloud API via UXC + curated OpenAPI schema"
default_prompt: "Use $whatsapp-openapi-skill to discover and execute WhatsApp Business Platform Cloud API operations through UXC with bearer-token auth, phone-number and business-profile reads, and guarded message sends."
FILE:references/usage-patterns.md
# WhatsApp Cloud API Skill - Usage Patterns
## Link Setup
```bash
command -v whatsapp-openapi-cli
uxc link whatsapp-openapi-cli https://graph.facebook.com/v25.0 \
--schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/whatsapp-openapi-skill/references/whatsapp-cloud.openapi.json
whatsapp-openapi-cli -h
```
## Auth Setup
```bash
uxc auth credential set whatsapp-cloud \
--auth-type bearer \
--secret-env WHATSAPP_CLOUD_ACCESS_TOKEN
uxc auth binding add \
--id whatsapp-cloud \
--host graph.facebook.com \
--path-prefix /v25.0 \
--scheme https \
--credential whatsapp-cloud \
--priority 100
```
Validate the binding:
```bash
uxc auth binding match https://graph.facebook.com/v25.0
```
## Read Examples
```bash
# List phone numbers under one WhatsApp Business account
whatsapp-openapi-cli get:/{waba_id}/phone_numbers waba_id=123456789012345
# Read one phone number's metadata
whatsapp-openapi-cli get:/{phone_number_id} phone_number_id=123456789012345 fields=display_phone_number,verified_name
# Read the business profile attached to the phone number
whatsapp-openapi-cli get:/{phone_number_id}/whatsapp_business_profile phone_number_id=123456789012345
```
## Write Examples (Confirm Intent First)
```bash
# Send a text message
whatsapp-openapi-cli post:/{phone_number_id}/messages '{"phone_number_id":"123456789012345","messaging_product":"whatsapp","to":"15551234567","type":"text","text":{"body":"Hello from UXC"}}'
# Send a template message
whatsapp-openapi-cli post:/{phone_number_id}/messages '{"phone_number_id":"123456789012345","messaging_product":"whatsapp","to":"15551234567","type":"template","template":{"name":"hello_world","language":{"code":"en_US"}}}'
# Update business profile fields
whatsapp-openapi-cli post:/{phone_number_id}/whatsapp_business_profile '{"phone_number_id":"123456789012345","about":"Support via WhatsApp","description":"Customer support team","email":"[email protected]","websites":["https://example.com"]}'
```
## Webhook Guidance
Webhook delivery is useful for inbound messages and status callbacks, but this skill does not host a receiver runtime. Keep webhook setup and verification outside `uxc`, and use this wrapper for request/response operations only.
## Fallback Equivalence
- `whatsapp-openapi-cli <operation> ...` is equivalent to
`uxc https://graph.facebook.com/v25.0 --schema-url <whatsapp_openapi_schema> <operation> ...`.
FILE:references/whatsapp-cloud.openapi.json
{
"openapi": "3.0.3",
"info": {
"title": "WhatsApp Cloud API (Curated)",
"version": "1.0.0",
"description": "Curated WhatsApp Cloud API surface for UXC messaging and profile workflows."
},
"servers": [
{
"url": "https://graph.facebook.com/v25.0"
}
],
"security": [
{
"WhatsAppBearerAuth": []
}
],
"paths": {
"/{waba_id}/phone_numbers": {
"get": {
"summary": "List phone numbers attached to a WhatsApp Business Account",
"parameters": [
{
"name": "waba_id",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "WhatsApp Business Account identifier"
},
{
"name": "fields",
"in": "query",
"required": false,
"schema": {
"type": "string"
},
"description": "Optional Graph fields selector for phone number records"
},
{
"name": "limit",
"in": "query",
"required": false,
"schema": {
"type": "integer",
"minimum": 1,
"maximum": 500
},
"description": "Maximum number of phone numbers to return"
}
],
"responses": {
"200": {
"description": "Phone number list response"
}
}
}
},
"/{phone_number_id}": {
"get": {
"summary": "Get metadata for one WhatsApp phone number",
"parameters": [
{
"name": "phone_number_id",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "WhatsApp phone number identifier"
},
{
"name": "fields",
"in": "query",
"required": false,
"schema": {
"type": "string",
"default": "display_phone_number,verified_name,quality_rating,code_verification_status"
},
"description": "Optional Graph fields selector for phone number metadata"
}
],
"responses": {
"200": {
"description": "Phone number metadata response"
}
}
}
},
"/{phone_number_id}/messages": {
"post": {
"summary": "Send a WhatsApp message from one phone number",
"parameters": [
{
"name": "phone_number_id",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "WhatsApp phone number identifier used to send the message"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SendMessageRequest"
}
}
}
},
"responses": {
"200": {
"description": "Send message response"
}
}
}
},
"/{phone_number_id}/whatsapp_business_profile": {
"get": {
"summary": "Get the WhatsApp business profile for a phone number",
"parameters": [
{
"name": "phone_number_id",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "WhatsApp phone number identifier"
},
{
"name": "fields",
"in": "query",
"required": false,
"schema": {
"type": "string",
"default": "about,address,description,email,profile_picture_url,vertical,websites"
},
"description": "Optional Graph fields selector for business profile fields"
}
],
"responses": {
"200": {
"description": "Business profile response"
}
}
},
"post": {
"summary": "Update the WhatsApp business profile for a phone number",
"parameters": [
{
"name": "phone_number_id",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "WhatsApp phone number identifier"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/BusinessProfileUpdateRequest"
}
}
}
},
"responses": {
"200": {
"description": "Business profile update response"
}
}
}
}
},
"components": {
"securitySchemes": {
"WhatsAppBearerAuth": {
"type": "http",
"scheme": "bearer",
"bearerFormat": "system user or permanent access token"
}
},
"schemas": {
"SendMessageRequest": {
"type": "object",
"required": [
"messaging_product",
"to",
"type"
],
"properties": {
"messaging_product": {
"type": "string",
"enum": [
"whatsapp"
],
"description": "Messaging product identifier"
},
"to": {
"type": "string",
"description": "Destination WhatsApp user phone number in international format"
},
"type": {
"type": "string",
"enum": [
"text",
"template",
"interactive",
"document",
"image"
],
"description": "Message type to send"
},
"recipient_type": {
"type": "string",
"enum": [
"individual"
],
"description": "Recipient type for Cloud API sends"
},
"context": {
"$ref": "#/components/schemas/MessageContext"
},
"text": {
"$ref": "#/components/schemas/TextMessage"
},
"template": {
"$ref": "#/components/schemas/TemplateMessage"
},
"interactive": {
"$ref": "#/components/schemas/InteractiveMessage"
},
"document": {
"$ref": "#/components/schemas/DocumentMessage"
},
"image": {
"$ref": "#/components/schemas/ImageMessage"
}
},
"additionalProperties": false
},
"MessageContext": {
"type": "object",
"properties": {
"message_id": {
"type": "string",
"description": "Message ID to reply to"
}
},
"additionalProperties": false
},
"TextMessage": {
"type": "object",
"required": [
"body"
],
"properties": {
"preview_url": {
"type": "boolean",
"description": "Whether to generate a link preview"
},
"body": {
"type": "string",
"description": "Text message body"
}
},
"additionalProperties": false
},
"TemplateMessage": {
"type": "object",
"required": [
"name",
"language"
],
"properties": {
"name": {
"type": "string",
"description": "Template name"
},
"language": {
"type": "object",
"required": [
"code"
],
"properties": {
"code": {
"type": "string",
"description": "Template language code such as en_US"
}
},
"additionalProperties": false
},
"components": {
"type": "array",
"items": {
"$ref": "#/components/schemas/TemplateComponent"
},
"description": "Optional template parameter components"
}
},
"additionalProperties": false
},
"TemplateComponent": {
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"type": "string",
"enum": [
"header",
"body",
"button"
]
},
"sub_type": {
"type": "string",
"description": "Button subtype when type=button"
},
"index": {
"type": "string",
"description": "Button index when type=button"
},
"parameters": {
"type": "array",
"items": {
"$ref": "#/components/schemas/TemplateParameter"
}
}
},
"additionalProperties": false
},
"TemplateParameter": {
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"type": "string",
"enum": [
"text",
"currency",
"date_time",
"image",
"document"
]
},
"text": {
"type": "string"
},
"currency": {
"type": "object",
"properties": {
"fallback_value": {
"type": "string"
},
"code": {
"type": "string"
},
"amount_1000": {
"type": "integer"
}
},
"additionalProperties": false
},
"date_time": {
"type": "object",
"properties": {
"fallback_value": {
"type": "string"
}
},
"additionalProperties": false
},
"image": {
"$ref": "#/components/schemas/ImageMediaObject"
},
"document": {
"$ref": "#/components/schemas/DocumentMediaObject"
}
},
"additionalProperties": false
},
"InteractiveMessage": {
"type": "object",
"required": [
"type",
"body",
"action"
],
"properties": {
"type": {
"type": "string",
"enum": [
"button",
"list"
],
"description": "Interactive message type"
},
"header": {
"$ref": "#/components/schemas/InteractiveHeader"
},
"body": {
"$ref": "#/components/schemas/InteractiveBody"
},
"footer": {
"$ref": "#/components/schemas/InteractiveFooter"
},
"action": {
"$ref": "#/components/schemas/InteractiveAction"
}
},
"additionalProperties": false
},
"InteractiveHeader": {
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"type": "string",
"enum": [
"text",
"image",
"document"
]
},
"text": {
"type": "string"
},
"image": {
"$ref": "#/components/schemas/ImageMediaObject"
},
"document": {
"$ref": "#/components/schemas/DocumentMediaObject"
}
},
"additionalProperties": false
},
"InteractiveBody": {
"type": "object",
"required": [
"text"
],
"properties": {
"text": {
"type": "string"
}
},
"additionalProperties": false
},
"InteractiveFooter": {
"type": "object",
"required": [
"text"
],
"properties": {
"text": {
"type": "string"
}
},
"additionalProperties": false
},
"InteractiveAction": {
"type": "object",
"properties": {
"buttons": {
"type": "array",
"minItems": 1,
"maxItems": 3,
"items": {
"$ref": "#/components/schemas/ReplyButton"
},
"description": "Reply buttons for interactive button messages"
},
"button": {
"type": "string",
"description": "Call-to-action text for interactive list messages"
},
"sections": {
"type": "array",
"items": {
"$ref": "#/components/schemas/InteractiveSection"
},
"description": "Sections for interactive list messages"
}
},
"additionalProperties": false
},
"ReplyButton": {
"type": "object",
"required": [
"type",
"reply"
],
"properties": {
"type": {
"type": "string",
"enum": [
"reply"
]
},
"reply": {
"type": "object",
"required": [
"id",
"title"
],
"properties": {
"id": {
"type": "string"
},
"title": {
"type": "string"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
},
"InteractiveSection": {
"type": "object",
"required": [
"rows"
],
"properties": {
"title": {
"type": "string"
},
"rows": {
"type": "array",
"items": {
"$ref": "#/components/schemas/InteractiveRow"
}
}
},
"additionalProperties": false
},
"InteractiveRow": {
"type": "object",
"required": [
"id",
"title"
],
"properties": {
"id": {
"type": "string"
},
"title": {
"type": "string"
},
"description": {
"type": "string"
}
},
"additionalProperties": false
},
"DocumentMessage": {
"allOf": [
{
"$ref": "#/components/schemas/DocumentMediaObject"
}
],
"description": "Document message payload"
},
"ImageMessage": {
"allOf": [
{
"$ref": "#/components/schemas/ImageMediaObject"
}
],
"description": "Image message payload"
},
"DocumentMediaObject": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Previously uploaded media ID"
},
"link": {
"type": "string",
"format": "uri",
"description": "Publicly reachable media URL"
},
"caption": {
"type": "string"
},
"filename": {
"type": "string"
}
},
"additionalProperties": false
},
"ImageMediaObject": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Previously uploaded media ID"
},
"link": {
"type": "string",
"format": "uri",
"description": "Publicly reachable media URL"
},
"caption": {
"type": "string"
}
},
"additionalProperties": false
},
"BusinessProfileUpdateRequest": {
"type": "object",
"properties": {
"about": {
"type": "string",
"description": "Business about text"
},
"address": {
"type": "string",
"description": "Business street address"
},
"description": {
"type": "string",
"description": "Longer business description"
},
"email": {
"type": "string",
"format": "email",
"description": "Business support email"
},
"profile_picture_url": {
"type": "string",
"format": "uri",
"description": "Business profile image URL"
},
"vertical": {
"type": "string",
"description": "Business category or vertical value"
},
"websites": {
"type": "array",
"maxItems": 2,
"items": {
"type": "string",
"format": "uri"
},
"description": "Business websites"
}
},
"additionalProperties": false
}
}
}
}
FILE:scripts/validate.sh
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "BASH_SOURCE[0]")/../../.." && pwd)"
SKILL_DIR="ROOT_DIR/skills/whatsapp-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/whatsapp-cloud.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["/{phone_number_id}/messages"]' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'OpenAPI schema missing /{phone_number_id}/messages path'
rg -q '^name:\s*whatsapp-openapi-skill\s*$' "SKILL_FILE" || fail 'invalid skill name'
rg -q '^description:\s*.+' "SKILL_FILE" || fail 'missing description'
rg -q 'command -v whatsapp-openapi-cli' "SKILL_FILE" || fail 'missing link-first command check'
rg -q 'uxc link whatsapp-openapi-cli https://graph.facebook.com/v25.0 --schema-url ' "SKILL_FILE" || fail 'missing fixed link create command with schema-url'
rg -q 'whatsapp-openapi-cli -h' "SKILL_FILE" || fail 'missing help-first host discovery example'
rg -F -q 'whatsapp-openapi-cli post:/{phone_number_id}/messages -h' "SKILL_FILE" || fail 'missing operation-level help example'
rg -q -- '--auth-type bearer' "SKILL_FILE" || fail 'missing bearer auth setup'
rg -q 'uxc auth binding match https://graph.facebook.com/v25.0' "SKILL_FILE" || fail 'missing binding match check'
rg -q 'v25.0' "SKILL_FILE" || fail 'missing API version pin guidance'
rg -q 'high-risk write' "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*"WhatsApp Cloud 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*".*\$whatsapp-openapi-skill.*"\s*$' "OPENAI_FILE" || fail 'default_prompt must mention $whatsapp-openapi-skill'
echo "skills/whatsapp-openapi-skill validation passed"
Use GoldRush MCP through UXC for multichain wallet balances, transfers, portfolio history, NFT ownership, token approvals, prices, and chain metadata via std...
---
name: goldrush-mcp-skill
description: Use GoldRush MCP through UXC for multichain wallet balances, transfers, portfolio history, NFT ownership, token approvals, prices, and chain metadata via stdio MCP with injected API-key auth.
---
# GoldRush MCP Skill
Use this skill to run GoldRush MCP operations through `uxc` using a fixed stdio endpoint.
Reuse the `uxc` skill for generic protocol discovery, output parsing, and auth/error handling rules.
## Prerequisites
- `uxc` is installed and available in `PATH`.
- `npx` is available in `PATH` (Node.js installed).
- Network access for first-time `@covalenthq/goldrush-mcp-server` package fetch.
- A GoldRush API key is available.
## Core Workflow
Endpoint candidate inputs before finalizing:
- Raw package form from docs: `npx @covalenthq/goldrush-mcp-server@latest`
- Reliable non-interactive form: `npx -y @covalenthq/goldrush-mcp-server@latest`
- This skill defaults to:
- `npx -y @covalenthq/goldrush-mcp-server@latest`
1. Verify protocol/path from official source and probe:
- Official source: `https://goldrush.dev/docs/goldrush-mcp-server`
- probe candidate endpoint with:
- `uxc --inject-env GOLDRUSH_API_KEY=$GOLDRUSH_API_KEY "npx -y @covalenthq/goldrush-mcp-server@latest" -h`
- cold start can take longer on first run because `npx` may need to download the package
2. Configure credential for repeatable auth:
- `uxc auth credential set goldrush-mcp --auth-type bearer --secret-env GOLDRUSH_API_KEY`
- `uxc auth credential set goldrush-mcp --auth-type bearer --secret-op op://Engineering/goldrush/api-key`
3. Use fixed link command by default:
- `command -v goldrush-mcp-cli`
- If missing, create it:
- `uxc link goldrush-mcp-cli "npx -y @covalenthq/goldrush-mcp-server@latest" --credential goldrush-mcp --inject-env GOLDRUSH_API_KEY={{secret}}`
- `goldrush-mcp-cli -h`
4. Inspect operation schema before execution:
- `goldrush-mcp-cli getAllChains -h`
- `goldrush-mcp-cli multichain_balances -h`
- `goldrush-mcp-cli transactions_for_address -h`
- `goldrush-mcp-cli historical_portfolio_value -h`
5. Prefer read-only discovery first, then expand into broader wallet-history or NFT scans.
## Capability Map
- Cross-chain overview:
- `getAllChains`
- `multichain_address_activity`
- `multichain_balances`
- `multichain_transactions`
- Wallet balances and portfolio:
- `token_balances`
- `historical_token_balances`
- `native_token_balance`
- `historical_portfolio_value`
- `historical_token_prices`
- Transfers and transactions:
- `erc20_token_transfers`
- `transaction`
- `transaction_summary`
- `transactions_for_address`
- `transactions_for_block`
- NFT and security:
- `nft_for_address`
- `nft_check_ownership`
- `token_approvals`
- Utility:
- `gas_prices`
- `log_events_by_address`
- `log_events_by_topic`
- `block`
- `block_heights`
GoldRush also exposes MCP resources such as `config://supported-chains`, `config://quote-currencies`, and `status://all-chains`. Inspect the live server after auth setup for the current full tool and resource list.
## Recommended Usage Pattern
1. Start with one focused read goal:
- multichain balances for a wallet
- recent transfers for an address
- historical portfolio value over time
- NFT ownership or token approval review
2. Run `-h` on the specific tool before the first real call.
3. Prefer a single wallet and chain first before running wide history 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 `goldrush-mcp-cli` as default command path.
- `goldrush-mcp-cli <operation> ...` is equivalent to `uxc --auth goldrush-mcp --inject-env GOLDRUSH_API_KEY={{secret}} "npx -y @covalenthq/goldrush-mcp-server@latest" <operation> ...` when the link is created as documented above.
- GoldRush uses a stdio MCP server started through `npx`, not a hosted HTTPS MCP endpoint. Expect slower cold starts on the first run.
- If help or the first call times out during initialization:
- rerun the same command after the package download finishes
- confirm `npx` is available in `PATH`
- confirm the key is being injected as `GOLDRUSH_API_KEY`
- The skill docs use bearer credential storage only as a secret container for `--inject-env`; GoldRush auth actually happens through the child environment variable, not an HTTP bearer header.
- Prefer wallet-scoped reads before wide transaction or log scans because some tools can produce large result sets.
- Do not assume tool argument names from memory; inspect `<operation> -h` first because GoldRush may revise MCP schemas independently of this skill.
## References
- Invocation patterns:
- `references/usage-patterns.md`
FILE:agents/openai.yaml
interface:
display_name: "GoldRush MCP"
short_description: "Multichain wallet, portfolio, NFT, and transaction data via GoldRush MCP"
default_prompt: "Use $goldrush-mcp-skill to query GoldRush MCP for multichain wallet balances, transfers, portfolio history, NFT ownership, token approvals, prices, and chain metadata with help-first inspection and injected API-key auth."
FILE:references/usage-patterns.md
# Usage Patterns
This skill defaults to fixed link command `goldrush-mcp-cli`.
## Setup
```bash
uxc auth credential set goldrush-mcp --auth-type bearer --secret-env GOLDRUSH_API_KEY
command -v goldrush-mcp-cli
uxc link goldrush-mcp-cli "npx -y @covalenthq/goldrush-mcp-server@latest" --credential goldrush-mcp --inject-env GOLDRUSH_API_KEY={{secret}}
goldrush-mcp-cli -h
```
Optional secret manager source:
```bash
uxc auth credential set goldrush-mcp --auth-type bearer --secret-op op://Engineering/goldrush/api-key
```
If the first `-h` run times out during initialization, rerun it once `npx` finishes downloading `@covalenthq/goldrush-mcp-server`.
## Help-First Discovery
```bash
goldrush-mcp-cli getAllChains -h
goldrush-mcp-cli multichain_balances -h
goldrush-mcp-cli transactions_for_address -h
goldrush-mcp-cli historical_portfolio_value -h
```
## Multichain Wallet Overview
Inspect supported chains:
```bash
goldrush-mcp-cli getAllChains
```
Inspect cross-chain balances:
```bash
goldrush-mcp-cli multichain_balances -h
```
Inspect wallet activity:
```bash
goldrush-mcp-cli multichain_address_activity -h
goldrush-mcp-cli multichain_transactions -h
```
## Portfolio And Transfers
Inspect historical portfolio value:
```bash
goldrush-mcp-cli historical_portfolio_value -h
```
Inspect ERC-20 transfers and wallet history:
```bash
goldrush-mcp-cli erc20_token_transfers -h
goldrush-mcp-cli transactions_for_address -h
goldrush-mcp-cli transaction_summary -h
```
## NFT, Security, And Utility
Inspect NFT ownership tools:
```bash
goldrush-mcp-cli nft_for_address -h
goldrush-mcp-cli nft_check_ownership -h
```
Inspect token approval and gas tools:
```bash
goldrush-mcp-cli token_approvals -h
goldrush-mcp-cli gas_prices -h
```
## Practical Rules
- Start with `getAllChains` or a wallet-specific balance read before running transaction history tools.
- Keep scopes narrow: one wallet, one chain, one date range when possible.
- Expect stdio cold-start delay on the first run because the MCP server is started through `npx`.
- The GoldRush key is injected into the subprocess as `GOLDRUSH_API_KEY`; it is not sent as an HTTP auth header by `uxc`.
- Use positional JSON if a tool expects arrays or nested filters.
## Fallback Equivalence
- `goldrush-mcp-cli <operation> ...` is equivalent to `uxc --auth goldrush-mcp --inject-env GOLDRUSH_API_KEY={{secret}} "npx -y @covalenthq/goldrush-mcp-server@latest" <operation> ...` when the link is created as documented above.
FILE:scripts/validate.sh
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "BASH_SOURCE[0]")/../../.." && pwd)"
SKILL_DIR="ROOT_DIR/skills/goldrush-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*goldrush-mcp-skill\s*$' "SKILL_FILE"; then
fail "SKILL.md frontmatter must define: name: goldrush-mcp-skill"
fi
if ! rg -q '^description:\s*.+' "SKILL_FILE"; then
fail "SKILL.md frontmatter must define a description"
fi
if ! rg -q '@covalenthq/goldrush-mcp-server@latest' "SKILL_FILE" "SKILL_DIR/references/usage-patterns.md"; then
fail "docs must reference the GoldRush MCP package endpoint"
fi
if ! rg -q 'GOLDRUSH_API_KEY' "SKILL_FILE" "SKILL_DIR/references/usage-patterns.md"; then
fail "docs must configure GOLDRUSH_API_KEY injection"
fi
if ! rg -q 'command -v goldrush-mcp-cli' "SKILL_FILE"; then
fail "SKILL.md must include link command existence check"
fi
if ! rg -q 'uxc link goldrush-mcp-cli "npx -y @covalenthq/goldrush-mcp-server@latest" --credential goldrush-mcp --inject-env GOLDRUSH_API_KEY=\{\{secret\}\}' "SKILL_FILE" "SKILL_DIR/references/usage-patterns.md"; then
fail "docs must include fixed link creation command with env injection"
fi
if ! rg -q 'goldrush-mcp-cli -h' "SKILL_FILE" "SKILL_DIR/references/usage-patterns.md"; then
fail "docs must use goldrush-mcp-cli help-first discovery"
fi
for op in getAllChains multichain_balances transactions_for_address historical_portfolio_value; do
if ! rg -q "op" "SKILL_FILE" "SKILL_DIR/references/usage-patterns.md"; then
fail "GoldRush docs must include op"
fi
done
if ! rg -q 'config://supported-chains|status://all-chains' "SKILL_FILE"; then
fail "GoldRush docs must mention MCP resources"
fi
if rg -q -- '--input-json|goldrush-mcp-cli list|goldrush-mcp-cli describe|goldrush-mcp-cli call' "SKILL_FILE" "SKILL_DIR/references/usage-patterns.md"; then
fail "GoldRush docs must not use list/describe/call/--input-json in default examples"
fi
if ! rg -q 'equivalent to `uxc --auth goldrush-mcp --inject-env GOLDRUSH_API_KEY=\{\{secret\}\} "npx -y @covalenthq/goldrush-mcp-server@latest"' "SKILL_FILE" "SKILL_DIR/references/usage-patterns.md"; then
fail "GoldRush docs must include single-point fallback equivalence guidance"
fi
if ! rg -q '^\s*display_name:\s*"GoldRush 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*".*\$goldrush-mcp-skill.*"\s*$' "OPENAI_FILE"; then
fail 'agents/openai.yaml default_prompt must mention $goldrush-mcp-skill'
fi
echo "skills/goldrush-mcp-skill validation passed"
Operate LINE Messaging API through UXC with a curated OpenAPI schema, bearer-token auth, and messaging-core guardrails.
---
name: line-openapi-skill
description: Operate LINE Messaging API through UXC with a curated OpenAPI schema, bearer-token auth, and messaging-core guardrails.
---
# LINE Messaging API Skill
Use this skill to run LINE Messaging 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.line.me`.
- Access to the curated OpenAPI schema URL:
- `https://raw.githubusercontent.com/holon-run/uxc/main/skills/line-openapi-skill/references/line-messaging.openapi.json`
- A LINE Messaging API channel access token.
## Scope
This skill covers a Messaging Core surface:
- bot identity lookup
- user profile lookup
- push and reply message sends
- quota and quota consumption reads
- webhook endpoint get/set/test operations
This skill does **not** cover:
- inbound webhook receiver runtime
- media/content download flows on `api-data.line.me`
- audience, narrowcast, rich menu, or account-management surfaces
- the full LINE Messaging API
## Authentication
LINE Messaging API uses `Authorization: Bearer <channel access token>`.
Configure one bearer credential and bind it to `api.line.me`:
```bash
uxc auth credential set line-channel \
--auth-type bearer \
--secret-env LINE_CHANNEL_ACCESS_TOKEN
uxc auth binding add \
--id line-channel \
--host api.line.me \
--scheme https \
--credential line-channel \
--priority 100
```
Validate the active mapping when auth looks wrong:
```bash
uxc auth binding match https://api.line.me
```
## Core Workflow
1. Use the fixed link command by default:
- `command -v line-openapi-cli`
- If missing, create it:
`uxc link line-openapi-cli https://api.line.me --schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/line-openapi-skill/references/line-messaging.openapi.json`
- `line-openapi-cli -h`
2. Inspect operation schema first:
- `line-openapi-cli get:/v2/bot/info -h`
- `line-openapi-cli get:/v2/bot/profile/{userId} -h`
- `line-openapi-cli post:/v2/bot/message/push -h`
3. Prefer read/setup validation before writes:
- `line-openapi-cli get:/v2/bot/info`
- `line-openapi-cli get:/v2/bot/message/quota`
- `line-openapi-cli get:/v2/bot/channel/webhook/endpoint`
4. Execute with key/value or positional JSON:
- key/value:
`line-openapi-cli get:/v2/bot/profile/{userId} userId=U1234567890abcdef`
- positional JSON:
`line-openapi-cli post:/v2/bot/message/push '{"to":"U1234567890abcdef","messages":[{"type":"text","text":"Hello from UXC"}]}'`
## Operation Groups
### Read / Lookup
- `get:/v2/bot/info`
- `get:/v2/bot/profile/{userId}`
- `get:/v2/bot/message/quota`
- `get:/v2/bot/message/quota/consumption`
- `get:/v2/bot/channel/webhook/endpoint`
### Messaging
- `post:/v2/bot/message/push`
- `post:/v2/bot/message/reply`
### Webhook Endpoint Management
- `put:/v2/bot/channel/webhook/endpoint`
- `post:/v2/bot/channel/webhook/test`
## Guardrails
- Keep automation on the JSON output envelope; do not use `--text`.
- Parse stable fields first: `ok`, `kind`, `protocol`, `data`, `error`.
- Use a channel access token with the scopes required by the target bot/channel configuration.
- `post:/v2/bot/message/push` and `post:/v2/bot/message/reply` are write/high-risk operations; require explicit user confirmation before execution.
- `replyToken` values are short-lived and webhook-derived. Use `post:/v2/bot/message/reply` only when the caller already has a valid token from a recent event.
- Webhook endpoint get/set/test calls configure delivery only; they do not provide a receiver runtime in `uxc`.
- This v1 skill stays on `https://api.line.me`; content retrieval endpoints on `https://api-data.line.me` are intentionally out of scope.
- `line-openapi-cli <operation> ...` is equivalent to `uxc https://api.line.me --schema-url <line_openapi_schema> <operation> ...`.
## References
- Usage patterns: `references/usage-patterns.md`
- Curated OpenAPI schema: `references/line-messaging.openapi.json`
- LINE Messaging API reference: https://developers.line.biz/en/reference/messaging-api/
FILE:agents/openai.yaml
interface:
display_name: "LINE Messaging API"
short_description: "Operate LINE Messaging API via UXC + curated OpenAPI schema"
default_prompt: "Use $line-openapi-skill to discover and execute LINE Messaging API operations through UXC with bearer-token auth, messaging-core scope, and webhook-management guardrails."
FILE:references/line-messaging.openapi.json
{
"openapi": "3.0.3",
"info": {
"title": "LINE Messaging API (Curated)",
"version": "1.0.0",
"description": "Curated LINE Messaging API surface for UXC messaging workflows."
},
"servers": [
{
"url": "https://api.line.me"
}
],
"security": [
{
"LineBearerAuth": []
}
],
"paths": {
"/v2/bot/info": {
"get": {
"summary": "Get bot information",
"responses": {
"200": {
"description": "Bot information response"
}
}
}
},
"/v2/bot/profile/{userId}": {
"get": {
"summary": "Get a user profile by user ID",
"parameters": [
{
"name": "userId",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "LINE user ID"
}
],
"responses": {
"200": {
"description": "Profile response"
}
}
}
},
"/v2/bot/message/push": {
"post": {
"summary": "Push a message to a user, group, or room",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PushMessageRequest"
}
}
}
},
"responses": {
"200": {
"description": "Push message response"
}
}
}
},
"/v2/bot/message/reply": {
"post": {
"summary": "Reply to an incoming event with messages",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ReplyMessageRequest"
}
}
}
},
"responses": {
"200": {
"description": "Reply message response"
}
}
}
},
"/v2/bot/message/quota": {
"get": {
"summary": "Get the monthly target limit for push messages",
"responses": {
"200": {
"description": "Quota response"
}
}
}
},
"/v2/bot/message/quota/consumption": {
"get": {
"summary": "Get the number of push messages sent this month",
"responses": {
"200": {
"description": "Quota consumption response"
}
}
}
},
"/v2/bot/channel/webhook/endpoint": {
"get": {
"summary": "Get the configured webhook endpoint URL",
"responses": {
"200": {
"description": "Webhook endpoint response"
}
}
},
"put": {
"summary": "Set or update the webhook endpoint URL",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/WebhookEndpointRequest"
}
}
}
},
"responses": {
"200": {
"description": "Webhook endpoint update response"
}
}
}
},
"/v2/bot/channel/webhook/test": {
"post": {
"summary": "Test webhook endpoint delivery",
"requestBody": {
"required": false,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/WebhookTestRequest"
}
}
}
},
"responses": {
"200": {
"description": "Webhook test response"
}
}
}
}
},
"components": {
"securitySchemes": {
"LineBearerAuth": {
"type": "http",
"scheme": "bearer",
"bearerFormat": "channel access token"
}
},
"schemas": {
"PushMessageRequest": {
"type": "object",
"required": [
"to",
"messages"
],
"properties": {
"to": {
"type": "string",
"description": "Destination user, group, or room ID"
},
"messages": {
"type": "array",
"minItems": 1,
"maxItems": 5,
"items": {
"$ref": "#/components/schemas/Message"
}
},
"notificationDisabled": {
"type": "boolean",
"description": "Disable push notification delivery for the message"
},
"customAggregationUnits": {
"type": "array",
"items": {
"type": "string"
},
"description": "Optional aggregation labels for analytics"
}
},
"additionalProperties": false
},
"ReplyMessageRequest": {
"type": "object",
"required": [
"replyToken",
"messages"
],
"properties": {
"replyToken": {
"type": "string",
"description": "Reply token from a webhook event"
},
"messages": {
"type": "array",
"minItems": 1,
"maxItems": 5,
"items": {
"$ref": "#/components/schemas/Message"
}
},
"notificationDisabled": {
"type": "boolean",
"description": "Disable push notification delivery for the reply"
}
},
"additionalProperties": false
},
"WebhookEndpointRequest": {
"type": "object",
"required": [
"endpoint"
],
"properties": {
"endpoint": {
"type": "string",
"format": "uri",
"description": "Webhook destination URL"
}
},
"additionalProperties": false
},
"WebhookTestRequest": {
"type": "object",
"properties": {
"endpoint": {
"type": "string",
"format": "uri",
"description": "Webhook destination URL to test. If omitted, the configured endpoint is used."
}
},
"additionalProperties": false
},
"Message": {
"oneOf": [
{
"$ref": "#/components/schemas/TextMessage"
},
{
"$ref": "#/components/schemas/ImageMessage"
},
{
"$ref": "#/components/schemas/VideoMessage"
},
{
"$ref": "#/components/schemas/AudioMessage"
},
{
"$ref": "#/components/schemas/LocationMessage"
},
{
"$ref": "#/components/schemas/StickerMessage"
}
]
},
"TextMessage": {
"type": "object",
"required": [
"type",
"text"
],
"properties": {
"type": {
"type": "string",
"enum": [
"text"
]
},
"text": {
"type": "string",
"description": "Text body to send"
},
"quoteToken": {
"type": "string",
"description": "Quote token for quoted replies when supported"
}
},
"additionalProperties": false
},
"ImageMessage": {
"type": "object",
"required": [
"type",
"originalContentUrl",
"previewImageUrl"
],
"properties": {
"type": {
"type": "string",
"enum": [
"image"
]
},
"originalContentUrl": {
"type": "string",
"format": "uri"
},
"previewImageUrl": {
"type": "string",
"format": "uri"
}
},
"additionalProperties": false
},
"VideoMessage": {
"type": "object",
"required": [
"type",
"originalContentUrl",
"previewImageUrl"
],
"properties": {
"type": {
"type": "string",
"enum": [
"video"
]
},
"originalContentUrl": {
"type": "string",
"format": "uri"
},
"previewImageUrl": {
"type": "string",
"format": "uri"
},
"trackingId": {
"type": "string"
}
},
"additionalProperties": false
},
"AudioMessage": {
"type": "object",
"required": [
"type",
"originalContentUrl",
"duration"
],
"properties": {
"type": {
"type": "string",
"enum": [
"audio"
]
},
"originalContentUrl": {
"type": "string",
"format": "uri"
},
"duration": {
"type": "integer",
"format": "int64",
"description": "Playback duration in milliseconds"
}
},
"additionalProperties": false
},
"LocationMessage": {
"type": "object",
"required": [
"type",
"title",
"address",
"latitude",
"longitude"
],
"properties": {
"type": {
"type": "string",
"enum": [
"location"
]
},
"title": {
"type": "string"
},
"address": {
"type": "string"
},
"latitude": {
"type": "number",
"format": "double"
},
"longitude": {
"type": "number",
"format": "double"
}
},
"additionalProperties": false
},
"StickerMessage": {
"type": "object",
"required": [
"type",
"packageId",
"stickerId"
],
"properties": {
"type": {
"type": "string",
"enum": [
"sticker"
]
},
"packageId": {
"type": "string"
},
"stickerId": {
"type": "string"
}
},
"additionalProperties": false
}
}
}
}
FILE:references/usage-patterns.md
# LINE Messaging API Skill - Usage Patterns
## Link Setup
```bash
command -v line-openapi-cli
uxc link line-openapi-cli https://api.line.me \
--schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/line-openapi-skill/references/line-messaging.openapi.json
line-openapi-cli -h
```
## Auth Setup
```bash
uxc auth credential set line-channel \
--auth-type bearer \
--secret-env LINE_CHANNEL_ACCESS_TOKEN
uxc auth binding add \
--id line-channel \
--host api.line.me \
--scheme https \
--credential line-channel \
--priority 100
```
Validate the binding:
```bash
uxc auth binding match https://api.line.me
```
## Read Examples
```bash
# Confirm bot identity
line-openapi-cli get:/v2/bot/info
# Look up one user profile
line-openapi-cli get:/v2/bot/profile/{userId} userId=U1234567890abcdef
# Inspect monthly message quota
line-openapi-cli get:/v2/bot/message/quota
# Inspect current month quota consumption
line-openapi-cli get:/v2/bot/message/quota/consumption
# Read current webhook endpoint configuration
line-openapi-cli get:/v2/bot/channel/webhook/endpoint
```
## Write Examples (Confirm Intent First)
```bash
# Push a text message
line-openapi-cli post:/v2/bot/message/push '{"to":"U1234567890abcdef","messages":[{"type":"text","text":"Hello from UXC"}]}'
# Reply to a recent inbound event using its replyToken
line-openapi-cli post:/v2/bot/message/reply '{"replyToken":"REPLY_TOKEN","messages":[{"type":"text","text":"Reply from UXC"}]}'
# Update the webhook delivery URL
line-openapi-cli put:/v2/bot/channel/webhook/endpoint '{"endpoint":"https://example.com/line/webhook"}'
# Trigger LINE's webhook endpoint verification
line-openapi-cli post:/v2/bot/channel/webhook/test '{"endpoint":"https://example.com/line/webhook"}'
```
## Fallback Equivalence
- `line-openapi-cli <operation> ...` is equivalent to
`uxc https://api.line.me --schema-url <line_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/line-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/line-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["/v2/bot/info"]' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'OpenAPI schema missing /v2/bot/info path'
rg -q '^name:\s*line-openapi-skill\s*$' "SKILL_FILE" || fail 'invalid skill name'
rg -q '^description:\s*.+' "SKILL_FILE" || fail 'missing description'
rg -q 'command -v line-openapi-cli' "SKILL_FILE" || fail 'missing link-first command check'
rg -q 'uxc link line-openapi-cli https://api.line.me --schema-url ' "SKILL_FILE" || fail 'missing fixed link create command with schema-url'
rg -q 'line-openapi-cli -h' "SKILL_FILE" || fail 'missing help-first host discovery example'
rg -q 'line-openapi-cli get:/v2/bot/info -h' "SKILL_FILE" || fail 'missing operation-level help example'
rg -q -- '--auth-type bearer' "SKILL_FILE" || fail 'missing bearer auth setup'
rg -q 'uxc auth binding match https://api.line.me' "SKILL_FILE" || fail 'missing binding match check'
rg -q 'replyToken' "SKILL_FILE" || fail 'missing reply token 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*"LINE Messaging 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*".*\$line-openapi-skill.*"\s*$' "OPENAI_FILE" || fail 'default_prompt must mention $line-openapi-skill'
echo "skills/line-openapi-skill validation passed"
Operate DefiLlama Pro analytics APIs through UXC with a curated OpenAPI schema, path-templated API-key auth, and read-first guardrails.
---
name: defillama-pro-openapi-skill
description: Operate DefiLlama Pro analytics APIs through UXC with a curated OpenAPI schema, path-templated API-key auth, and read-first guardrails.
---
# DefiLlama Pro API Skill
Use this skill to run DefiLlama Pro 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://pro-api.llama.fi`.
- Access to the curated OpenAPI schema URL:
- `https://raw.githubusercontent.com/holon-run/uxc/main/skills/defillama-pro-openapi-skill/references/defillama-pro.openapi.json`
- A DefiLlama Pro API key.
## Scope
This skill covers a read-first analytics surface:
- protocol TVL list and per-protocol detail
- chain overview reads
- current token price lookups
- yield pool discovery
- yield chart history
- stablecoin dominance reads
This skill does **not** cover:
- write operations or account management
- the public unauthenticated host variants
- the full DefiLlama Pro endpoint surface
## Authentication
DefiLlama Pro places the API key in the request path, between the host and the endpoint path.
Configure one API-key credential with a request path prefix template:
```bash
uxc auth credential set defillama-pro \
--auth-type api_key \
--secret-env DEFILLAMA_PRO_API_KEY \
--path-prefix-template "/{{secret}}"
uxc auth binding add \
--id defillama-pro \
--host pro-api.llama.fi \
--scheme https \
--credential defillama-pro \
--priority 100
```
Validate the active mapping when auth looks wrong:
```bash
uxc auth binding match https://pro-api.llama.fi
```
## Core Workflow
1. Use the fixed link command by default:
- `command -v defillama-pro-openapi-cli`
- If missing, create it:
`uxc link defillama-pro-openapi-cli https://pro-api.llama.fi --schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/defillama-pro-openapi-skill/references/defillama-pro.openapi.json`
- `defillama-pro-openapi-cli -h`
2. Inspect operation schema first:
- `defillama-pro-openapi-cli get:/api/protocols -h`
- `defillama-pro-openapi-cli get:/coins/prices/current/{coins} -h`
- `defillama-pro-openapi-cli get:/yields/chart/{pool} -h`
3. Prefer narrow read validation before broader reads:
- `defillama-pro-openapi-cli get:/api/v2/chains`
- `defillama-pro-openapi-cli get:/api/protocol/{protocol} protocol=aave`
- `defillama-pro-openapi-cli get:/yields/pools`
4. Execute with key/value parameters:
- `defillama-pro-openapi-cli get:/api/protocol/{protocol} protocol=aave`
- `defillama-pro-openapi-cli get:/coins/prices/current/{coins} coins=ethereum:0x0000000000000000000000000000000000000000 searchWidth=4h`
- `defillama-pro-openapi-cli get:/stablecoins/stablecoindominance/{chain} chain=ethereum`
## Operation Groups
### Protocol And Chain Analytics
- `get:/api/protocols`
- `get:/api/protocol/{protocol}`
- `get:/api/v2/chains`
### Prices, Yields, And Stablecoins
- `get:/coins/prices/current/{coins}`
- `get:/yields/pools`
- `get:/yields/chart/{pool}`
- `get:/stablecoins/stablecoindominance/{chain}`
## 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 admin support.
- This skill assumes the Pro host and key-in-path auth model. Do not bind the same credential to a different path shape without checking the upstream docs first.
- API keys are sensitive because they appear in the request path. Use `--secret-env` or `--secret-op`, not shell history literals, when possible.
- Avoid sharing raw daemon logs when troubleshooting this integration. The key is part of the request path, so if you inspect `~/.uxc/daemon/daemon.log`, sanitize, rotate, or delete the log after debugging and avoid verbose logging unless necessary.
- `defillama-pro-openapi-cli <operation> ...` is equivalent to `uxc https://pro-api.llama.fi --schema-url <defillama_pro_openapi_schema> <operation> ...`.
## References
- Usage patterns: `references/usage-patterns.md`
- Curated OpenAPI schema: `references/defillama-pro.openapi.json`
- DefiLlama API docs: https://defillama.com/docs/api
- DefiLlama Pro docs: https://defillama.com/pro-api/docs
FILE:agents/openai.yaml
interface:
display_name: "DefiLlama Pro API"
short_description: "Operate DefiLlama Pro analytics reads via UXC + curated OpenAPI schema"
default_prompt: "Use $defillama-pro-openapi-skill to discover and execute DefiLlama Pro analytics operations through UXC with path-templated API-key auth and read-first guardrails."
FILE:references/defillama-pro.openapi.json
{
"openapi": "3.0.3",
"info": {
"title": "DefiLlama Pro Curated API",
"version": "1.0.0",
"description": "Curated read-only DefiLlama Pro analytics surface for UXC."
},
"servers": [
{
"url": "https://pro-api.llama.fi"
}
],
"paths": {
"/api/protocols": {
"get": {
"operationId": "listProtocols",
"summary": "List protocol TVL entries",
"responses": {
"200": {
"description": "Protocols response",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
}
},
"/api/protocol/{protocol}": {
"get": {
"operationId": "getProtocol",
"summary": "Get one protocol by slug",
"parameters": [
{
"name": "protocol",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Protocol detail response",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
},
"/api/v2/chains": {
"get": {
"operationId": "listChains",
"summary": "List chain overview entries",
"responses": {
"200": {
"description": "Chains response",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
}
},
"/coins/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
}
}
}
}
}
}
},
"/yields/pools": {
"get": {
"operationId": "listYieldPools",
"summary": "List yield pools",
"responses": {
"200": {
"description": "Yield pools response",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
},
"/yields/chart/{pool}": {
"get": {
"operationId": "getYieldChart",
"summary": "Get a yield chart for one pool",
"parameters": [
{
"name": "pool",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Yield chart response",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
}
},
"/stablecoins/stablecoindominance/{chain}": {
"get": {
"operationId": "getStablecoinDominance",
"summary": "Get stablecoin dominance for one chain",
"parameters": [
{
"name": "chain",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Stablecoin dominance response",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
}
}
}
FILE:references/usage-patterns.md
# DefiLlama Pro API Skill - Usage Patterns
## Link Setup
```bash
command -v defillama-pro-openapi-cli
uxc link defillama-pro-openapi-cli https://pro-api.llama.fi \
--schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/defillama-pro-openapi-skill/references/defillama-pro.openapi.json
defillama-pro-openapi-cli -h
```
## Auth Setup
```bash
uxc auth credential set defillama-pro \
--auth-type api_key \
--secret-env DEFILLAMA_PRO_API_KEY \
--path-prefix-template "/{{secret}}"
uxc auth binding add \
--id defillama-pro \
--host pro-api.llama.fi \
--scheme https \
--credential defillama-pro \
--priority 100
```
Validate the binding:
```bash
uxc auth binding match https://pro-api.llama.fi
```
## Read Examples
```bash
# List tracked protocols and their top-level TVL metrics
defillama-pro-openapi-cli get:/api/protocols
# Read one protocol in detail
defillama-pro-openapi-cli get:/api/protocol/{protocol} protocol=aave
# Read chain overview metrics
defillama-pro-openapi-cli get:/api/v2/chains
# Read current prices for one or more chain-prefixed assets
defillama-pro-openapi-cli get:/coins/prices/current/{coins} \
coins=ethereum:0x0000000000000000000000000000000000000000,coingecko:bitcoin \
searchWidth=4h
# Discover yield pools
defillama-pro-openapi-cli get:/yields/pools
# Read one pool's yield chart history
defillama-pro-openapi-cli get:/yields/chart/{pool} pool=747c1d2a-c668-4682-b9f9-296708a3dd90
# Read stablecoin dominance for one chain
defillama-pro-openapi-cli get:/stablecoins/stablecoindominance/{chain} chain=ethereum
```
## Fallback Equivalence
- `defillama-pro-openapi-cli <operation> ...` is equivalent to
`uxc https://pro-api.llama.fi --schema-url <defillama_pro_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-pro-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-pro.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["/api/protocols"] and .paths["/yields/pools"]' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'OpenAPI schema missing expected DefiLlama Pro paths'
rg -q '^name:\s*defillama-pro-openapi-skill\s*$' "SKILL_FILE" || fail 'invalid skill name'
rg -q '^description:\s*.+' "SKILL_FILE" || fail 'missing description'
rg -q 'command -v defillama-pro-openapi-cli' "SKILL_FILE" || fail 'missing link-first command check'
rg -q 'uxc link defillama-pro-openapi-cli https://pro-api.llama.fi --schema-url ' "SKILL_FILE" || fail 'missing fixed link create command with schema-url'
rg -q 'defillama-pro-openapi-cli -h' "SKILL_FILE" || fail 'missing help-first host discovery example'
rg -q 'defillama-pro-openapi-cli get:/api/protocols -h' "SKILL_FILE" || fail 'missing operation-level help example'
rg -q -- '--path-prefix-template "/\{\{secret\}\}"' "SKILL_FILE" || fail 'missing path-prefix auth setup'
rg -q 'uxc auth binding match https://pro-api.llama.fi' "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*"DefiLlama Pro 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*".*\$defillama-pro-openapi-skill.*"\s*$' "OPENAI_FILE" || fail 'default_prompt must mention $defillama-pro-openapi-skill'
echo "skills/defillama-pro-openapi-skill validation passed"
Operate DefiLlama public yield APIs through UXC with a curated OpenAPI schema and read-first guardrails.
---
name: defillama-yields-openapi-skill
description: Operate DefiLlama public yield APIs through UXC with a curated OpenAPI schema and read-first guardrails.
---
# DefiLlama Yields API Skill
Use this skill to run DefiLlama public yield 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://yields.llama.fi`.
- Access to the curated OpenAPI schema URL:
- `https://raw.githubusercontent.com/holon-run/uxc/main/skills/defillama-yields-openapi-skill/references/defillama-yields.openapi.json`
## Scope
This skill covers a public read-only yield surface on `yields.llama.fi`:
- yield pool discovery
- per-pool chart history
This skill does **not** cover:
- write operations
- protocol or chain overview endpoints from `api.llama.fi`
- price endpoints from `coins.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-yields-openapi-cli`
- If missing, create it:
`uxc link defillama-yields-openapi-cli https://yields.llama.fi --schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/defillama-yields-openapi-skill/references/defillama-yields.openapi.json`
- `defillama-yields-openapi-cli -h`
2. Inspect operation schema first:
- `defillama-yields-openapi-cli get:/pools -h`
- `defillama-yields-openapi-cli get:/chart/{pool} -h`
3. Prefer narrow read validation before broader reads:
- `defillama-yields-openapi-cli get:/pools`
- `defillama-yields-openapi-cli get:/chart/{pool} pool=747c1d2a-c668-4682-b9f9-296708a3dd90`
## Operations
- `get:/pools`
- `get:/chart/{pool}`
## 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.
- Public DefiLlama data is split across multiple hosts; this skill intentionally wraps only `yields.llama.fi`.
- `defillama-yields-openapi-cli <operation> ...` is equivalent to `uxc https://yields.llama.fi --schema-url <defillama_yields_openapi_schema> <operation> ...`.
## References
- Usage patterns: `references/usage-patterns.md`
- Curated OpenAPI schema: `references/defillama-yields.openapi.json`
- DefiLlama API docs: https://defillama.com/docs/api
FILE:agents/openai.yaml
interface:
display_name: "DefiLlama Yields API"
short_description: "Operate DefiLlama public yield reads via UXC"
default_prompt: "Use $defillama-yields-openapi-skill to discover and execute DefiLlama public yield operations through UXC with read-first guardrails."
FILE:references/defillama-yields.openapi.json
{
"openapi": "3.0.3",
"info": {
"title": "DefiLlama Yields Curated API",
"version": "1.0.0",
"description": "Curated read-only DefiLlama public yields surface for UXC."
},
"servers": [
{
"url": "https://yields.llama.fi"
}
],
"paths": {
"/pools": {
"get": {
"operationId": "listYieldPools",
"summary": "List yield pools",
"responses": {
"200": {
"description": "Yield pools response",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
},
"/chart/{pool}": {
"get": {
"operationId": "getYieldChart",
"summary": "Get a yield chart for one pool",
"parameters": [
{
"name": "pool",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Yield chart response",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
}
}
}
}
FILE:references/usage-patterns.md
# DefiLlama Yields API Skill - Usage Patterns
## Link Setup
```bash
command -v defillama-yields-openapi-cli
uxc link defillama-yields-openapi-cli https://yields.llama.fi \
--schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/defillama-yields-openapi-skill/references/defillama-yields.openapi.json
defillama-yields-openapi-cli -h
```
This public skill does not require auth.
## Read Examples
```bash
# Discover yield pools
defillama-yields-openapi-cli get:/pools
# Read one pool's yield chart history
defillama-yields-openapi-cli get:/chart/{pool} pool=747c1d2a-c668-4682-b9f9-296708a3dd90
```
## Fallback Equivalence
- `defillama-yields-openapi-cli <operation> ...` is equivalent to
`uxc https://yields.llama.fi --schema-url <defillama_yields_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-yields-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-yields.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["/pools"] and .paths["/chart/{pool}"]' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'OpenAPI schema missing expected DefiLlama yield paths'
rg -q '^name:\s*defillama-yields-openapi-skill\s*$' "SKILL_FILE" || fail 'invalid skill name'
rg -q 'command -v defillama-yields-openapi-cli' "SKILL_FILE" || fail 'missing link-first command check'
rg -q 'uxc link defillama-yields-openapi-cli https://yields.llama.fi --schema-url ' "SKILL_FILE" || fail 'missing fixed link create command'
rg -q 'defillama-yields-openapi-cli get:/pools -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 Yields API"\s*$' "OPENAI_FILE" || fail 'missing display_name'
rg -q '^\s*default_prompt:\s*".*\$defillama-yields-openapi-skill.*"\s*$' "OPENAI_FILE" || fail 'default_prompt must mention $defillama-yields-openapi-skill'
echo "skills/defillama-yields-openapi-skill validation passed"
Use Gate MCP through UXC for public spot and futures market data workflows with a fixed streamable-http endpoint and read-first guardrails.
---
name: gate-mcp-skill
description: Use Gate MCP through UXC for public spot and futures market data workflows with a fixed streamable-http endpoint and read-first guardrails.
---
# Gate MCP Skill
Use this skill to run Gate public market data workflows through `uxc` + MCP.
Reuse the `uxc` skill for shared MCP execution, output parsing, and generic auth guidance.
## Prerequisites
- `uxc` is installed and available in `PATH`.
- Network access to `https://api.gatemcp.ai/mcp`.
## Scope
This skill covers the official Gate MCP surface for:
- public spot market discovery
- public spot tickers, trades, order books, and candlesticks
- public futures contracts, tickers, trades, order books, funding, and premium data
This skill does **not** cover:
- private account or trading workflows
- Gate REST v4 signed APIs
- wallet, funding, or portfolio actions
## Endpoint
Use Gate's official MCP endpoint:
- `https://api.gatemcp.ai/mcp`
## Core Workflow
1. Use the fixed link command by default:
- `command -v gate-mcp-cli`
- If missing, create it:
`uxc link gate-mcp-cli https://api.gatemcp.ai/mcp`
- `gate-mcp-cli -h`
2. Inspect tool and argument help before execution:
- `gate-mcp-cli cex_spot_get_spot_tickers -h`
- `gate-mcp-cli cex_spot_get_spot_order_book -h`
- `gate-mcp-cli cex_fx_get_fx_tickers -h`
- `gate-mcp-cli cex_fx_get_fx_order_book -h`
3. Prefer narrow spot or futures reads with explicit instrument identifiers:
- `gate-mcp-cli cex_spot_get_spot_tickers currency_pair=BTC_USDT`
- `gate-mcp-cli cex_spot_get_spot_order_book currency_pair=BTC_USDT limit=20`
- `gate-mcp-cli cex_fx_get_fx_tickers contract=BTC_USDT`
- `gate-mcp-cli cex_fx_get_fx_funding_rate contract=BTC_USDT`
## Operations
### Spot
- `cex_spot_list_currencies`
- `cex_spot_list_currency_pairs`
- `cex_spot_get_currency`
- `cex_spot_get_currency_pair`
- `cex_spot_get_spot_tickers`
- `cex_spot_get_spot_order_book`
- `cex_spot_get_spot_trades`
- `cex_spot_get_spot_candlesticks`
### Futures
- `cex_fx_list_fx_contracts`
- `cex_fx_get_fx_contract`
- `cex_fx_get_fx_tickers`
- `cex_fx_get_fx_order_book`
- `cex_fx_get_fx_trades`
- `cex_fx_get_fx_candlesticks`
- `cex_fx_get_fx_funding_rate`
- `cex_fx_get_fx_premium_index`
- `cex_fx_list_fx_liq_orders`
## 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.
- Prefer `currency_pair` values like `BTC_USDT` for spot and `contract` values like `BTC_USDT` for futures unless help output indicates a different contract name.
- `gate-mcp-cli <operation> ...` is equivalent to `uxc https://api.gatemcp.ai/mcp <operation> ...`.
## References
- Usage patterns: `references/usage-patterns.md`
- Official Gate for AI / MCP docs: https://www.gate.com/gate-mcp-skills
- Gate MCP setup article: https://www.gate.com/ru/help/gateforai/gateforaibasics/50102/gate-for-ai-one-click-integration-with-major-ai-agents-no-api-keys-required-zero-barriers
FILE:agents/openai.yaml
interface:
display_name: "Gate MCP"
short_description: "Public spot and futures market data via Gate MCP"
default_prompt: "Use $gate-mcp-skill to inspect and execute Gate MCP public market-data tools with help-first discovery and read-only guardrails."
FILE:references/usage-patterns.md
# Usage Patterns
This skill defaults to fixed link command `gate-mcp-cli`.
## Setup
```bash
command -v gate-mcp-cli
uxc link gate-mcp-cli https://api.gatemcp.ai/mcp
gate-mcp-cli -h
```
## Help-First Discovery
```bash
gate-mcp-cli -h
gate-mcp-cli cex_spot_get_spot_tickers -h
gate-mcp-cli cex_spot_get_spot_order_book -h
gate-mcp-cli cex_fx_get_fx_tickers -h
gate-mcp-cli cex_fx_get_fx_order_book -h
```
## Spot Reads
```bash
gate-mcp-cli cex_spot_list_currencies
gate-mcp-cli cex_spot_list_currency_pairs
gate-mcp-cli cex_spot_get_spot_tickers currency_pair=BTC_USDT
gate-mcp-cli cex_spot_get_spot_order_book currency_pair=BTC_USDT limit=20
gate-mcp-cli cex_spot_get_spot_trades currency_pair=BTC_USDT limit=20
gate-mcp-cli cex_spot_get_spot_candlesticks currency_pair=BTC_USDT interval=1h limit=20
```
## Futures Reads
```bash
gate-mcp-cli cex_fx_list_fx_contracts
gate-mcp-cli cex_fx_get_fx_contract contract=BTC_USDT
gate-mcp-cli cex_fx_get_fx_tickers contract=BTC_USDT
gate-mcp-cli cex_fx_get_fx_order_book contract=BTC_USDT limit=20
gate-mcp-cli cex_fx_get_fx_funding_rate contract=BTC_USDT
gate-mcp-cli cex_fx_get_fx_trades contract=BTC_USDT limit=20
```
## Fallback Equivalence
- `gate-mcp-cli <operation> ...` is equivalent to
`uxc https://api.gatemcp.ai/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/gate-mcp-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" "SKILL_DIR/scripts/validate.sh"; 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
rg -q '^name:\s*gate-mcp-skill\s*$' "SKILL_FILE" || fail 'invalid skill name'
rg -q '^description:\s*.+' "SKILL_FILE" || fail 'missing description'
rg -q 'https://api\.gatemcp\.ai/mcp' "SKILL_FILE" "USAGE_FILE" || fail 'missing Gate MCP endpoint'
rg -q 'command -v gate-mcp-cli' "SKILL_FILE" || fail 'missing link-first check'
rg -q 'uxc link gate-mcp-cli https://api\.gatemcp\.ai/mcp' "SKILL_FILE" "USAGE_FILE" || fail 'missing fixed link command'
rg -q 'gate-mcp-cli -h' "SKILL_FILE" "USAGE_FILE" || fail 'missing help-first discovery'
rg -q 'references/usage-patterns\.md' "SKILL_FILE" || fail 'missing usage-patterns reference'
rg -q 'equivalent to `uxc https://api\.gatemcp\.ai/mcp' "SKILL_FILE" "USAGE_FILE" || fail 'missing fallback equivalence guidance'
for op in cex_spot_get_spot_tickers cex_spot_get_spot_order_book cex_fx_get_fx_tickers cex_fx_get_fx_order_book cex_fx_get_fx_funding_rate; do
rg -q "op" "SKILL_FILE" "USAGE_FILE" || fail "missing op"
done
rg -q 'read-only' "SKILL_FILE" || fail 'missing read-only guardrail'
if rg -q -- '--input-json|gate-mcp-cli list|gate-mcp-cli describe|gate-mcp-cli call' "SKILL_FILE" "USAGE_FILE"; then
fail 'found banned legacy 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*"Gate MCP"\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*".*\$gate-mcp-skill.*"\s*$' "OPENAI_FILE" || fail 'default_prompt must mention $gate-mcp-skill'
echo "skills/gate-mcp-skill validation passed"
Use Chrome DevTools MCP through UXC over local stdio for page navigation, DOM/a11y snapshots, network inspection, console inspection, and performance tooling...
---
name: chrome-devtools-mcp-skill
description: Use Chrome DevTools MCP through UXC over local stdio for page navigation, DOM/a11y snapshots, network inspection, console inspection, and performance tooling, with a live-browser autoConnect default and optional browserUrl or isolated fallback modes.
---
# Chrome DevTools MCP Skill
Use this skill to run Chrome DevTools MCP operations through `uxc` using a fixed stdio endpoint.
Reuse the `uxc` skill for generic MCP discovery, daemon reuse, JSON envelope parsing, and error handling.
## Prerequisites
- `uxc` is installed and available in `PATH`.
- `npx` is available in `PATH` (Node.js installed).
- Chrome 144+ is running locally with remote debugging enabled from `chrome://inspect/#remote-debugging` if you use the default live-browser flow.
- Network access is available for first-time `chrome-devtools-mcp` package fetch.
## Core Workflow (Chrome DevTools MCP-Specific)
Endpoint candidate inputs before finalizing:
- Raw package form from official docs:
- `npx chrome-devtools-mcp@latest`
- Reliable non-interactive form:
- `npx -y chrome-devtools-mcp@latest`
- Default live-browser endpoint for this skill:
- `npx -y chrome-devtools-mcp@latest --autoConnect --no-usage-statistics`
- Explicit browser-url endpoint:
- `npx -y chrome-devtools-mcp@latest --browserUrl http://127.0.0.1:9222 --no-usage-statistics`
- Fallback isolated endpoint:
- `npx -y chrome-devtools-mcp@latest --headless --isolated --no-usage-statistics`
- Running local Chrome auto-connect mode:
- `npx -y chrome-devtools-mcp@latest --autoConnect --no-usage-statistics`
1. Verify protocol/path from official source and probe:
- Official source:
- `https://github.com/ChromeDevTools/chrome-devtools-mcp`
- probe candidate endpoints with:
- `uxc "npx -y chrome-devtools-mcp@latest --autoConnect --no-usage-statistics" -h`
- Confirm protocol is MCP stdio (`protocol == "mcp"` in envelope).
2. Detect auth requirement explicitly:
- Run host help or a minimal read call and inspect envelope.
- Default local stdio flow requires no OAuth/API key.
- Existing Chrome attachment requires remote debugging to be enabled separately, but not API auth.
3. Use a fixed link command by default:
- `command -v chrome-devtools-mcp-cli`
- If missing, create it:
- `uxc link chrome-devtools-mcp-cli "npx -y chrome-devtools-mcp@latest --autoConnect --no-usage-statistics"`
- Optional explicit browser-url link:
- `command -v chrome-devtools-mcp-port`
- `uxc link chrome-devtools-mcp-port "npx -y chrome-devtools-mcp@latest --browserUrl http://127.0.0.1:9222 --no-usage-statistics"`
- Optional isolated fallback link:
- `command -v chrome-devtools-mcp-isolated`
- `uxc link chrome-devtools-mcp-isolated "npx -y chrome-devtools-mcp@latest --headless --isolated --no-usage-statistics"`
- `chrome-devtools-mcp-cli -h`
4. Inspect operation schema before execution:
- `chrome-devtools-mcp-cli new_page -h`
- `chrome-devtools-mcp-cli take_snapshot -h`
- `chrome-devtools-mcp-cli list_network_requests -h`
- `chrome-devtools-mcp-cli lighthouse_audit -h`
5. Prefer read-first interaction:
- Start with `new_page`, `list_pages`, `take_snapshot`, `list_network_requests`, or `list_console_messages`.
6. Confirm before mutating page state:
- `click`
- `fill`
- `fill_form`
- `press_key`
- `upload_file`
- `evaluate_script`
- `handle_dialog`
## Guardrails
- Keep automation on the JSON output envelope; do not rely on `--text`.
- Use `chrome-devtools-mcp-cli` as the default command path.
- Prefer the live-browser default endpoint when you need real logged-in state, current tabs, network diagnostics, console inspection, or performance analysis.
- Prefer `--autoConnect` first when browser-side remote debugging is available.
- Use `chrome-devtools-mcp-port` only when you intentionally run a Chrome instance with `--remote-debugging-port=9222`.
- If no debuggable Chrome is available, fallback to `chrome-devtools-mcp-isolated`.
- Prefer `take_snapshot` over screenshots for model-action loops.
- Prefer `list_network_requests` / `get_network_request` over raw script evaluation when inspecting network behavior.
- Treat `lighthouse_audit`, `performance_start_trace`, and `take_memory_snapshot` as heavier operations; use them intentionally.
- Use `evaluate_script` only when an existing higher-level DevTools tool cannot answer the question.
## References
- Invocation patterns:
- `references/usage-patterns.md`
FILE:agents/openai.yaml
interface:
display_name: "Chrome DevTools MCP"
short_description: "Drive Chrome DevTools MCP via UXC for page, network, console, and performance inspection"
default_prompt: "Use $chrome-devtools-mcp-skill to inspect pages, console output, network activity, and performance through Chrome DevTools MCP over UXC with help-first discovery and safe action guardrails."
FILE:references/usage-patterns.md
# Usage Patterns
This skill defaults to a live-browser stdio endpoint:
`npx -y chrome-devtools-mcp@latest --autoConnect --no-usage-statistics`
This skill defaults to the fixed link command `chrome-devtools-mcp-cli`.
Create it when missing:
```bash
command -v chrome-devtools-mcp-cli
uxc link chrome-devtools-mcp-cli "npx -y chrome-devtools-mcp@latest --autoConnect --no-usage-statistics"
```
## Live Chrome Setup
Use this skill when your Chrome build exposes remote debugging settings at `chrome://inspect/#remote-debugging` and you have enabled them there.
```bash
chrome-devtools-mcp-cli -h
```
## Explicit Port-Based Attachment
Use this mode when you intentionally launch Chrome with `--remote-debugging-port=9222`.
```bash
command -v chrome-devtools-mcp-port
uxc link chrome-devtools-mcp-port "npx -y chrome-devtools-mcp@latest --browserUrl http://127.0.0.1:9222 --no-usage-statistics"
```
## Isolated Fallback
Use this mode when you do not have a debuggable Chrome instance available.
```bash
command -v chrome-devtools-mcp-isolated
uxc link chrome-devtools-mcp-isolated "npx -y chrome-devtools-mcp@latest --headless --isolated --no-usage-statistics"
```
## Discover And Inspect
```bash
chrome-devtools-mcp-cli -h
chrome-devtools-mcp-cli new_page -h
chrome-devtools-mcp-cli take_snapshot -h
chrome-devtools-mcp-cli list_network_requests -h
chrome-devtools-mcp-cli lighthouse_audit -h
```
## Read-First Flow
Open a page:
```bash
chrome-devtools-mcp-cli new_page url=https://example.com
```
Capture a text snapshot:
```bash
chrome-devtools-mcp-cli take_snapshot verbose=true
```
Inspect network traffic:
```bash
chrome-devtools-mcp-cli list_network_requests pageSize=20
```
Inspect console messages:
```bash
chrome-devtools-mcp-cli list_console_messages
```
Run a Lighthouse audit:
```bash
chrome-devtools-mcp-cli lighthouse_audit
```
## Action Flow (Confirm High-Impact Actions First)
Click a page element by snapshot uid:
```bash
chrome-devtools-mcp-cli click uid=6_1
```
Fill an input:
```bash
chrome-devtools-mcp-cli fill uid=7_1 value='search text'
```
Evaluate JavaScript:
```bash
chrome-devtools-mcp-cli evaluate_script function='() => document.title'
```
## Bare JSON Positional Example
```bash
chrome-devtools-mcp-cli new_page '{"url":"https://example.com","timeout":10000}'
```
## Output Parsing
Rely on envelope fields:
- Success: `ok == true`, consume `data`
- Failure: `ok == false`, inspect `error.code` and `error.message`
## Fallback Equivalence
- `chrome-devtools-mcp-cli <operation> ...` is equivalent to `uxc "npx -y chrome-devtools-mcp@latest --autoConnect --no-usage-statistics" <operation> ...`.
- If link setup is temporarily unavailable, use the direct `uxc "<endpoint>" ...` form as fallback.
FILE:scripts/validate.sh
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "BASH_SOURCE[0]")/../../.." && pwd)"
SKILL_DIR="ROOT_DIR/skills/chrome-devtools-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
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*chrome-devtools-mcp-skill\s*$' "SKILL_FILE"; then
fail "SKILL.md frontmatter must define: name: chrome-devtools-mcp-skill"
fi
if ! rg -q '^description:\s*.+' "SKILL_FILE"; then
fail "SKILL.md frontmatter must define a description"
fi
if ! rg -q 'npx -y chrome-devtools-mcp@latest --autoConnect --no-usage-statistics' "SKILL_FILE" "SKILL_DIR/references/usage-patterns.md"; then
fail "docs must include fixed live Chrome DevTools MCP autoConnect endpoint"
fi
if ! rg -q 'command -v chrome-devtools-mcp-cli' "SKILL_FILE" "SKILL_DIR/references/usage-patterns.md"; then
fail "docs must include default link existence check"
fi
if ! rg -q 'uxc link chrome-devtools-mcp-cli "npx -y chrome-devtools-mcp@latest --autoConnect --no-usage-statistics"' "SKILL_FILE" "SKILL_DIR/references/usage-patterns.md"; then
fail "docs must include fixed link creation command"
fi
if ! rg -q 'chrome-devtools-mcp-port' "SKILL_FILE" "SKILL_DIR/references/usage-patterns.md"; then
fail "docs must include optional browserUrl link"
fi
if ! rg -q 'chrome-devtools-mcp-isolated' "SKILL_FILE" "SKILL_DIR/references/usage-patterns.md"; then
fail "docs must include optional isolated fallback link"
fi
if ! rg -q -- '--autoConnect' "SKILL_FILE" "SKILL_DIR/references/usage-patterns.md"; then
fail "docs must include autoConnect mode"
fi
if ! rg -q -- '--browserUrl http://127.0.0.1:9222' "SKILL_FILE" "SKILL_DIR/references/usage-patterns.md"; then
fail "docs must include browserUrl attach mode"
fi
if ! rg -q -- '--headless --isolated --no-usage-statistics' "SKILL_FILE" "SKILL_DIR/references/usage-patterns.md"; then
fail "docs must include isolated fallback mode"
fi
if ! rg -q -- '--autoConnect' "SKILL_FILE" "SKILL_DIR/references/usage-patterns.md"; then
fail "docs must include autoConnect mode"
fi
if ! rg -q 'official source' "SKILL_FILE"; then
fail "SKILL.md must mention official-source discovery step"
fi
if ! rg -q 'probe candidate endpoints with' "SKILL_FILE"; then
fail "SKILL.md must include probe step before finalizing endpoint"
fi
if ! rg -q 'no OAuth/API key' "SKILL_FILE"; then
fail "SKILL.md must explicitly document auth detection result"
fi
if ! rg -q 'chrome-devtools-mcp-cli -h' "SKILL_FILE" "SKILL_DIR/references/usage-patterns.md"; then
fail "docs must include help-first command"
fi
if ! rg -q 'chrome-devtools-mcp-cli new_page -h' "SKILL_FILE" "SKILL_DIR/references/usage-patterns.md"; then
fail "docs must include operation help for new_page"
fi
if ! rg -q 'new_page url=' "SKILL_FILE" "SKILL_DIR/references/usage-patterns.md"; then
fail "docs must include key=value example"
fi
if ! rg -q "new_page .*'\\{.*\\}'" "SKILL_FILE" "SKILL_DIR/references/usage-patterns.md"; then
fail "docs must include bare JSON positional example"
fi
if ! rg -q 'references/usage-patterns.md' "SKILL_FILE"; then
fail "SKILL.md must reference usage-patterns.md"
fi
if ! rg -q 'equivalent to `uxc "npx -y chrome-devtools-mcp@latest --autoConnect --no-usage-statistics"' "SKILL_FILE" "SKILL_DIR/references/usage-patterns.md"; then
fail "docs must include fallback equivalence guidance"
fi
if rg -q -- 'chrome-devtools-mcp-cli (list|describe|call)(\s|$)|--input-json|--args .*\{' "SKILL_FILE" "SKILL_DIR/references/usage-patterns.md"; then
fail "docs must not use legacy list/describe/call/--input-json/--args JSON forms"
fi
if ! rg -q '^\s*display_name:\s*"Chrome DevTools 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*".*\$chrome-devtools-mcp-skill.*"\s*$' "OPENAI_FILE"; then
fail 'agents/openai.yaml default_prompt must mention $chrome-devtools-mcp-skill'
fi
echo "skills/chrome-devtools-mcp-skill validation passed"
Use Crypto.com MCP through UXC for exchange market data workflows with help-first discovery and read-only guardrails.
---
name: crypto-com-mcp-skill
description: Use Crypto.com MCP through UXC for exchange market data workflows with help-first discovery and read-only guardrails.
---
# Crypto.com MCP Skill
Use this skill to run Crypto.com exchange market data workflows through `uxc` + MCP.
Reuse the `uxc` skill for shared MCP execution, output parsing, and auth handling.
## Prerequisites
- `uxc` is installed and available in `PATH`.
- Network access to `https://mcp.crypto.com/market-data/mcp`.
- Access to the official Crypto.com MCP docs:
- `https://mcp.crypto.com/docs`
## Scope
This skill covers the official Crypto.com MCP surface for:
- exchange market discovery
- ticker and order book style reads
- read-only market data workflows
This skill does **not** cover:
- exchange trading or account writes
- private account workflows
- non-MCP REST or WebSocket product families
## Endpoint
Use the official Crypto.com MCP endpoint:
- `https://mcp.crypto.com/market-data/mcp`
## Core Workflow
1. Use the fixed link command by default:
- `command -v crypto-com-mcp-cli`
- If missing, create it:
`uxc link crypto-com-mcp-cli https://mcp.crypto.com/market-data/mcp`
2. Inspect tool and argument help before execution:
- `crypto-com-mcp-cli -h`
- `crypto-com-mcp-cli get_ticker -h`
- `crypto-com-mcp-cli get_book -h`
- `crypto-com-mcp-cli get_candlestick -h`
3. Prefer read-only market queries and keep instruments and limits narrow:
- `crypto-com-mcp-cli get_ticker instrument_name=BTC_USDT`
- `crypto-com-mcp-cli get_book instrument_name=BTC_USDT depth=20`
- `crypto-com-mcp-cli get_candlestick instrument_name=BTC_USDT timeframe=1h`
## Operations
- `get_instruments`
- `get_instrument`
- `get_ticker`
- `get_tickers`
- `get_book`
- `get_index_price`
- `get_mark_price`
- `get_candlestick`
- `get_trades`
## 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.
- Treat this as market-data only. Do not imply trading, balances, or private account access.
- `crypto-com-mcp-cli <operation> ...` is equivalent to `uxc https://mcp.crypto.com/market-data/mcp <operation> ...`.
## References
- Usage patterns: `references/usage-patterns.md`
- Official Crypto.com MCP docs: https://mcp.crypto.com/docs
FILE:agents/openai.yaml
interface:
display_name: "Crypto.com MCP"
short_description: "Exchange market data via the official Crypto.com MCP surface"
default_prompt: "Use $crypto-com-mcp-skill to inspect and run Crypto.com MCP market-data workflows through UXC with help-first discovery and read-only guardrails."
FILE:references/usage-patterns.md
# Crypto.com MCP Skill - Usage Patterns
## Link Setup
```bash
command -v crypto-com-mcp-cli
uxc link crypto-com-mcp-cli https://mcp.crypto.com/market-data/mcp
crypto-com-mcp-cli -h
```
## Help-First Discovery
```bash
crypto-com-mcp-cli -h
crypto-com-mcp-cli get_ticker -h
crypto-com-mcp-cli get_book -h
crypto-com-mcp-cli get_candlestick -h
```
## Read Examples
```bash
# List supported instruments
crypto-com-mcp-cli get_instruments
# Inspect a single instrument
crypto-com-mcp-cli get_instrument instrument_name=BTC_USDT
# Read a single ticker
crypto-com-mcp-cli get_ticker instrument_name=BTC_USDT
# Read an order book snapshot
crypto-com-mcp-cli get_book instrument_name=BTC_USDT depth=20
# Read recent candles
crypto-com-mcp-cli get_candlestick instrument_name=BTC_USDT timeframe=1h
# Read recent trades
crypto-com-mcp-cli get_trades instrument_name=BTC_USDT limit=20
```
## Fallback Equivalence
- `crypto-com-mcp-cli <operation> ...` is equivalent to
`uxc https://mcp.crypto.com/market-data/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/crypto-com-mcp-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
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
rg -q '^name:\s*crypto-com-mcp-skill\s*$' "SKILL_FILE" || fail 'invalid skill name'
rg -q '^description:\s*.+' "SKILL_FILE" || fail 'missing description'
rg -q 'command -v crypto-com-mcp-cli' "SKILL_FILE" || fail 'missing link-first command check'
rg -q 'https://mcp\.crypto\.com/market-data/mcp' "SKILL_FILE" "USAGE_FILE" || fail 'missing fixed Crypto.com MCP endpoint'
rg -q 'uxc link crypto-com-mcp-cli https://mcp\.crypto\.com/market-data/mcp' "SKILL_FILE" "USAGE_FILE" || fail 'missing fixed link create command'
rg -F -q 'https://mcp.crypto.com/docs' "SKILL_FILE" "USAGE_FILE" || fail 'missing official docs reference'
for op in get_instruments get_ticker get_book get_candlestick get_trades; do
rg -q "op" "SKILL_FILE" "USAGE_FILE" || fail "missing op"
done
rg -q 'read-only' "SKILL_FILE" || fail 'missing read-only guardrail'
if rg -q -- '--input-json|crypto-com-mcp-cli list|crypto-com-mcp-cli describe|crypto-com-mcp-cli call' "SKILL_FILE" "USAGE_FILE"; then
fail 'found banned legacy 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*"Crypto.com MCP"\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*".*\$crypto-com-mcp-skill.*"\s*$' "OPENAI_FILE" || fail 'default_prompt must mention $crypto-com-mcp-skill'
echo "skills/crypto-com-mcp-skill validation passed"
Operate DefiLlama public analytics APIs through UXC with a curated OpenAPI schema and read-first guardrails.
---
name: defillama-openapi-skill
description: Operate DefiLlama public analytics APIs through UXC with a curated OpenAPI schema and read-first guardrails.
---
# DefiLlama Public API Skill
Use this skill to run DefiLlama public 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.llama.fi`.
- Access to the curated OpenAPI schema URL:
- `https://raw.githubusercontent.com/holon-run/uxc/main/skills/defillama-openapi-skill/references/defillama-public.openapi.json`
## Scope
This skill covers a public read-only analytics surface on `api.llama.fi`:
- protocol TVL list
- per-protocol detail
- chain overview reads
This skill does **not** cover:
- write operations or account management
- DefiLlama Pro key-in-path auth
- split-host public services such as `coins.llama.fi` and `yields.llama.fi`
- the full DefiLlama public API surface
## Authentication
This public skill does not require authentication.
## Core Workflow
1. Use the fixed link command by default:
- `command -v defillama-openapi-cli`
- If missing, create it:
`uxc link defillama-openapi-cli https://api.llama.fi --schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/defillama-openapi-skill/references/defillama-public.openapi.json`
- `defillama-openapi-cli -h`
2. Inspect operation schema first:
- `defillama-openapi-cli get:/protocols -h`
- `defillama-openapi-cli get:/protocol/{protocol} -h`
- `defillama-openapi-cli get:/v2/chains -h`
3. Prefer narrow read validation before broader reads:
- `defillama-openapi-cli get:/v2/chains`
- `defillama-openapi-cli get:/protocols`
- `defillama-openapi-cli get:/protocol/{protocol} protocol=aave`
4. Execute with key/value parameters:
- `defillama-openapi-cli get:/protocol/{protocol} protocol=aave`
- `defillama-openapi-cli get:/v2/chains`
## Operations
- `get:/protocols`
- `get:/protocol/{protocol}`
- `get:/v2/chains`
## 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 admin support.
- Public DefiLlama data is split across multiple hosts. This skill intentionally stays on `api.llama.fi`; use the separate Pro skill when you need the unified Pro host.
- `defillama-openapi-cli <operation> ...` is equivalent to `uxc https://api.llama.fi --schema-url <defillama_openapi_schema> <operation> ...`.
## References
- Usage patterns: `references/usage-patterns.md`
- Curated OpenAPI schema: `references/defillama-public.openapi.json`
- DefiLlama API docs: https://defillama.com/docs/api
FILE:agents/openai.yaml
interface:
display_name: "DefiLlama Public API"
short_description: "Operate DefiLlama public protocol and chain analytics reads via UXC"
default_prompt: "Use $defillama-openapi-skill to discover and execute DefiLlama public analytics operations through UXC with read-first guardrails."
FILE:references/defillama-public.openapi.json
{
"openapi": "3.0.3",
"info": {
"title": "DefiLlama Public Curated API",
"version": "1.0.0",
"description": "Curated read-only DefiLlama public analytics surface for UXC."
},
"servers": [
{
"url": "https://api.llama.fi"
}
],
"paths": {
"/protocols": {
"get": {
"operationId": "listProtocols",
"summary": "List protocol TVL entries",
"responses": {
"200": {
"description": "Protocols response",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
}
},
"/protocol/{protocol}": {
"get": {
"operationId": "getProtocol",
"summary": "Get one protocol by slug",
"parameters": [
{
"name": "protocol",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Protocol detail response",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
},
"/v2/chains": {
"get": {
"operationId": "listChains",
"summary": "List chain overview entries",
"responses": {
"200": {
"description": "Chains response",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
}
}
}
}
FILE:references/usage-patterns.md
# DefiLlama Public API Skill - Usage Patterns
## Link Setup
```bash
command -v defillama-openapi-cli
uxc link defillama-openapi-cli https://api.llama.fi \
--schema-url https://raw.githubusercontent.com/holon-run/uxc/main/skills/defillama-openapi-skill/references/defillama-public.openapi.json
defillama-openapi-cli -h
```
This public skill does not require auth.
## Read Examples
```bash
# List tracked protocols and their top-level TVL metrics
defillama-openapi-cli get:/protocols
# Read one protocol in detail
defillama-openapi-cli get:/protocol/{protocol} protocol=aave
# Read chain overview metrics
defillama-openapi-cli get:/v2/chains
```
## Fallback Equivalence
- `defillama-openapi-cli <operation> ...` is equivalent to
`uxc https://api.llama.fi --schema-url <defillama_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-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-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' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'invalid OpenAPI schema JSON or missing .openapi/.paths'
jq -e '.paths["/protocols"] and .paths["/protocol/{protocol}"] and .paths["/v2/chains"]' "SCHEMA_FILE" >/dev/null 2>&1 || fail 'OpenAPI schema missing expected DefiLlama public paths'
rg -q '^name:\s*defillama-openapi-skill\s*$' "SKILL_FILE" || fail 'invalid skill name'
rg -q '^description:\s*.+' "SKILL_FILE" || fail 'missing description'
rg -q 'command -v defillama-openapi-cli' "SKILL_FILE" || fail 'missing link-first command check'
rg -q 'uxc link defillama-openapi-cli https://api.llama.fi --schema-url ' "SKILL_FILE" || fail 'missing fixed link create command with schema-url'
rg -q 'defillama-openapi-cli get:/protocols -h' "SKILL_FILE" || fail 'missing protocol list help example'
rg -q 'defillama-openapi-cli get:/v2/chains -h' "SKILL_FILE" || fail 'missing chain help example'
rg -q 'does not require auth' "USAGE_FILE" || fail 'missing no-auth guidance'
rg -q 'split across multiple hosts' "SKILL_FILE" || fail 'missing split-host 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*"DefiLlama Public 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*".*\$defillama-openapi-skill.*"\s*$' "OPENAI_FILE" || fail 'default_prompt must mention $defillama-openapi-skill'
echo "skills/defillama-openapi-skill validation passed"