{"id":"d1baa24c-5e2f-4e09-8d50-326bdae0ad95","entityType":"agent","slug":"clawhub-jlacroix82-api-proxy","name":"api-gateway","canonicalUrl":"https://www.xpersona.co/agent/clawhub-jlacroix82-api-proxy","canonicalPath":"/agent/clawhub-jlacroix82-api-proxy","generatedAt":"2026-10-10T14:42:50.672Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-10T12:24:36.329Z","emptyReason":null},"description":"Smart proxy for external API calls with retry, caching, rate limiting, and fallback providers. Key management with masked display. Zero external dependencies.","descriptionLabel":"Source description","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 1.4K downloads reported by the source. Last updated 10/10/2026.","installCommand":"clawhub skill install s175p518b8g47fx6r9zyvs95ks876t4t:api-proxy","sourceUrl":"https://clawhub.ai/jlacroix82/api-proxy","homepage":"https://clawhub.ai/jlacroix82/skills/api-proxy","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/jlacroix82/api-proxy","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/jlacroix82/skills/api-proxy","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":63,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"api-gateway technical dossier on Xpersona with agent coverage, OPENCLEW support, and live trust metadata."},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-10T12:24:36.329Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-10T12:24:36.329Z","emptyReason":null},"stars":null,"forks":null,"downloads":1434,"packageName":null,"latestVersion":"1.1.12","tractionLabel":"1.4K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-10T12:24:36.265Z","emptyReason":null},"lastUpdatedAt":"2026-10-10T12:24:36.329Z","lastCrawledAt":"2026-10-10T12:24:36.265Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-11T12:24:36.265Z","lastVerifiedAt":null,"highlights":[{"version":"1.1.12","createdAt":"2026-09-13T12:34:51.177Z","changelog":"**api-proxy 1.1.12** - Cache and rate-limit keys are now SHA-256 digests; endpoint URLs and request bodies are no longer stored in plaintext. - Documentation updated to reflect improved on-disk privacy for cache and rate-limit files (see SKILL.md). - Minor refinements to external dependency listing and internal documentation for clarity. - Added VET-REPORT.md for enhanced visibility. - Removed obsolete skill-card.md.","fileCount":9,"zipByteSize":24120},{"version":"1.1.11","createdAt":"2026-08-15T20:08:38.602Z","changelog":"**Changelog for api-proxy v1.1.11** - Cache and rate-limit keys are now SHA-256 digests; actual URLs and request bodies are never stored on disk in plaintext. - Updated documentation to clarify enhanced privacy: cache.json and rate-limits.json use hashed keys (provider + endpoint/body digest) instead of writing endpoint URLs or request bodies. - Added `crypto` and `os` to the list of Node.js built-ins used. - Removed unused or redundant documentation file (skill-card.md). - Minor documentation improvements and clarifications.","fileCount":8,"zipByteSize":23363},{"version":"1.1.9","createdAt":"2026-08-04T16:48:15.641Z","changelog":"- Removed deprecated file `skill-card.md` for simpler maintenance. - Documentation updates in `README.md` and `SKILL.md` for accuracy and clarity. - Updated configuration reference in `clawhub.yaml`. - No changes to core functionality.","fileCount":8,"zipByteSize":21562},{"version":"1.1.8","createdAt":"2026-08-04T15:28:35.005Z","changelog":"api-proxy v1.1.8 - Improved privacy documentation: SKILL.md now explicitly states that request and response bodies are never written to persistent logs or caches by default. - Clarified metadata-only caching: Detailed that only response status, timestamp, headers, and body length are stored, unless full caching is manually enabled. - Minor language and formatting improvements for accuracy and clarity. - Obsolete or redundant documentation (skill-card.md) was removed.","fileCount":8,"zipByteSize":21119},{"version":"1.1.7","createdAt":"2026-08-03T11:22:00.516Z","changelog":"Version 1.1.7 - Clarified SKILL.md documentation on use of environment variables: only environment variables named in the `PROVIDER_API_KEY` pattern (e.g., `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`) will be used for API keys, not arbitrary env references. - Removed reference to using `env:NAME` in provider configuration for API key lookup. - Minor text and warning improvements in SKILL.md for accuracy and security clarity. - Removed outdated `skill-card.md` file.","fileCount":8,"zipByteSize":20849},{"version":"1.1.6","createdAt":"2026-08-03T02:46:29.063Z","changelog":"- Internal documentation updated: removed redundant file (skill-card.md) and revised SKILL.md. - Minor maintenance: small adjustments to primary source, config, and docs. - No changes to core functionality or user-facing commands.","fileCount":8,"zipByteSize":20639},{"version":"1.1.5","createdAt":"2026-08-02T19:57:38.230Z","changelog":"- Updated Clawhub integration, including changes to `clawhub.yaml` for improved configuration. - Removed the obsolete `skill-card.md` file. - Minor maintenance and code updates in `api-gateway.js`. - Documentation in `SKILL.md` remains unchanged.","fileCount":8,"zipByteSize":19863},{"version":"1.1.4","createdAt":"2026-08-02T16:52:56.522Z","changelog":"api-proxy 1.1.4 - Updated api-gateway.js and clawhub.yaml for improved functionality or configuration. - Removed the skill-card.md file. - No changes to core features or documented API from user perspective.","fileCount":8,"zipByteSize":19468}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s175p518b8g47fx6r9zyvs95ks876t4t:api-proxy","setupComplexity":"low","setupSteps":["Install using `clawhub skill install s175p518b8g47fx6r9zyvs95ks876t4t:api-proxy` in an isolated environment before connecting it to live workloads.","No published capability contract is available yet, so validate auth and request/response behavior manually.","Review the upstream CLAWHUB listing at https://clawhub.ai/jlacroix82/api-proxy before using production credentials."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-jlacroix82-api-proxy/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-jlacroix82-api-proxy/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-jlacroix82-api-proxy/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-jlacroix82-api-proxy/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-jlacroix82-api-proxy/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-jlacroix82-api-proxy/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-10T14:42:50.667Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-jlacroix82-api-proxy/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-jlacroix82-api-proxy/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-jlacroix82-api-proxy/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-jlacroix82-api-proxy/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-10T12:24:36.329Z","emptyReason":null},"readme":"Skill: api-gateway\n\nOwner: jlacroix82\n\nSummary: Smart proxy for external API calls with retry, caching, rate limiting, and fallback providers. Key management with masked display. Zero external dependencies.\n\nTags: latest:1.1.8, security-fix:1.1.0\n\nVersion history:\n\nv1.1.12 | 2026-09-13T12:34:51.177Z | auto\n\n**api-proxy 1.1.12**\n\n- Cache and rate-limit keys are now SHA-256 digests; endpoint URLs and request bodies are no longer stored in plaintext.\n- Documentation updated to reflect improved on-disk privacy for cache and rate-limit files (see SKILL.md).\n- Minor refinements to external dependency listing and internal documentation for clarity.\n- Added VET-REPORT.md for enhanced visibility.\n- Removed obsolete skill-card.md.\n\nv1.1.11 | 2026-08-15T20:08:38.602Z | auto\n\n**Changelog for api-proxy v1.1.11**\n\n- Cache and rate-limit keys are now SHA-256 digests; actual URLs and request bodies are never stored on disk in plaintext.\n- Updated documentation to clarify enhanced privacy: cache.json and rate-limits.json use hashed keys (provider + endpoint/body digest) instead of writing endpoint URLs or request bodies.\n- Added `crypto` and `os` to the list of Node.js built-ins used.\n- Removed unused or redundant documentation file (skill-card.md).\n- Minor documentation improvements and clarifications.\n\nv1.1.9 | 2026-08-04T16:48:15.641Z | auto\n\n- Removed deprecated file `skill-card.md` for simpler maintenance.\n- Documentation updates in `README.md` and `SKILL.md` for accuracy and clarity.\n- Updated configuration reference in `clawhub.yaml`.\n- No changes to core functionality.\n\nv1.1.8 | 2026-08-04T15:28:35.005Z | auto\n\napi-proxy v1.1.8\n\n- Improved privacy documentation: SKILL.md now explicitly states that request and response bodies are never written to persistent logs or caches by default.\n- Clarified metadata-only caching: Detailed that only response status, timestamp, headers, and body length are stored, unless full caching is manually enabled.\n- Minor language and formatting improvements for accuracy and clarity.\n- Obsolete or redundant documentation (skill-card.md) was removed.\n\nv1.1.7 | 2026-08-03T11:22:00.516Z | auto\n\nVersion 1.1.7\n\n- Clarified SKILL.md documentation on use of environment variables: only environment variables named in the `PROVIDER_API_KEY` pattern (e.g., `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`) will be used for API keys, not arbitrary env references.\n- Removed reference to using `env:NAME` in provider configuration for API key lookup.\n- Minor text and warning improvements in SKILL.md for accuracy and security clarity.\n- Removed outdated `skill-card.md` file.\n\nv1.1.6 | 2026-08-03T02:46:29.063Z | auto\n\n- Internal documentation updated: removed redundant file (skill-card.md) and revised SKILL.md.\n- Minor maintenance: small adjustments to primary source, config, and docs.\n- No changes to core functionality or user-facing commands.\n\nv1.1.5 | 2026-08-02T19:57:38.230Z | auto\n\n- Updated Clawhub integration, including changes to `clawhub.yaml` for improved configuration.\n- Removed the obsolete `skill-card.md` file.\n- Minor maintenance and code updates in `api-gateway.js`.\n- Documentation in `SKILL.md` remains unchanged.\n\nv1.1.4 | 2026-08-02T16:52:56.522Z | auto\n\napi-proxy 1.1.4\n\n- Updated api-gateway.js and clawhub.yaml for improved functionality or configuration.\n- Removed the skill-card.md file.\n- No changes to core features or documented API from user perspective.\n\nv1.1.3 | 2026-07-23T01:56:50.995Z | user\n\nSecurity overhaul: strict domain allowlist per provider (replaces string.includes), chmod 0600 on keys.json, metadata-only response cache by default with opt-in full body, coarse request log (no endpoints/query strings), env-var key override (PROVIDER_API_KEY), atomic file writes, prominent SKILL.md warnings about plaintext keys and outbound requests\n\nv1.1.2 | 2026-07-22T17:48:26.407Z | auto\n\n- Improved security documentation: The SKILL.md now includes a warning about outbound HTTP requests to arbitrary endpoints, clarifying provider token injection and endpoint trust.\n- Documentation update: Expanded and clarified the explanation about persistent cache and request logs, including the number of entries retained.\n- Maintenance: Removed skill-card.md to reduce redundant or unused documentation files.\n- No core functionality or interface changes; update is documentation-focused.\n\nv1.1.1 | 2026-07-22T16:03:45.373Z | user\n\nSecurity improvements: clarified data storage warnings, updated security documentation, fixed descriptions to match actual behavior.\n\nv1.1.0 | 2026-07-20T01:56:19.231Z | user\n\nProvider URL allowlist for API key safety, endpoint validation, 0600 on config files, --provider command for custom base URLs. 26 tests.\n\nv1.0.0 | 2026-07-18T22:03:11.419Z | user\n\nInitial release: 26/26 self-tests, HTTP proxy with circuit breaker, response caching, rate limiting, API key masking, configurable retry. Zero external dependencies.\n\nArchive index:\n\nArchive v1.1.12: 9 files, 24120 bytes\n\nFiles: api-gateway.js (35648b), clawhub.yaml (2685b), README.md (4066b), skill-card.md (2611b), SKILL.md (14404b), test/run-tests.js (3485b), tests/run-self-tests.js (6632b), VET-REPORT.md (691b), _meta.json (129b)\n\nFile v1.1.12:SKILL.md\n\n---\nname: api-gateway\nversion: 1.1.12\ndescription: Smart proxy for external API calls with retry, caching, rate limiting, and fallback providers. PERSISTS: API keys (chmod 0600 plaintext in keys.json), request/response cache metadata, and request logs. Network: outbound HTTPS only, with a strict provider-domain allowlist. Caches metadata by default; full response bodies are opt-in per provider. Cache and rate-limit keys are SHA-256 digests, so request bodies and endpoint URLs are never written to disk in plaintext.\n---\n\n# API Gateway ⚡\n\n> **Read this first.** This skill makes outbound HTTPS calls and writes plaintext API keys to disk. By installing or running it, you accept responsibility for the security of the keys you provide and the endpoints you target.\n\n**Stop duplicating API logic. Start routing through one smart gateway.**\n\n## What This Skill Does\n\nAPI Gateway is a local Node.js HTTP client wrapper that gives one call:\n\n- **Retry with exponential backoff** (3 attempts, 1s/2s/4s)\n- **Response caching** (default 5 min TTL, metadata-only)\n- **Rate-limit handling** (parses `x-ratelimit-remaining`, auto-fallback)\n- **Circuit breaker** (5-failure open, 30s cooldown, auto-recover)\n- **API key management** (masked display, chmod 0600 storage, env-var override)\n- **Fallback providers** (configurable per-provider chain)\n\n## ⚠️ Important Warnings\n\n### Outbound HTTPS Requests to Whitelisted Provider Domains\n`--call <provider> <endpoint>` sends HTTPS requests and, for configured providers, attaches a `Authorization: Bearer <key>` header. **The provider allowlist is strict: it is a domain-match check, not a `string.includes()` check.** A URL like `https://attacker.com/api?provider=openai` will NOT receive the key because the hostname must match the provider's registered allowlist entry. Review the allowlist in `--keys` output before adding sensitive keys.\n\n### API Keys Stored in Plaintext on Disk\nAPI keys saved via `--keys add` are written to `memory/api-gateway/keys.json` in plaintext, with file permissions set to `0600` (owner read/write only). The key is NEVER echoed back. Anyone with shell access to the workspace as the same user can still read it. For higher assurance, prefer environment variables: `OPENAI_API_KEY=sk-...` — API Gateway auto-detects any `PROVIDER_API_KEY` variable (e.g. `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`) and uses it without disk storage. It does NOT read arbitrary `env:NAME` references — only the `PROVIDER_API_KEY` pattern — so unrelated secrets are never pulled in.\n\n### Persistent Data Files (Disclosed Up Front)\nThe following files persist in `memory/api-gateway/` after any operation:\n- `keys.json` — API key storage, chmod 0600\n- `cache.json` — **Metadata-only by default** (status code, timestamp, response headers, response body *length*). The full response **body** is NOT stored unless you explicitly enable it per provider via `--cache-full <provider>`. **Cache keys are provider name + a SHA-256 digest of the endpoint path and request body** — the endpoint and the body themselves are never written to this file.\n- `request-log.json` — Provider name, status class (2xx/4xx/5xx), timestamp. Endpoint URLs, query strings, and request/response **bodies are NOT written here.** (Note: if *you* pass a URL or prompt inside a request body to `--call`, that body travels to the provider but is never persisted to the log or cache by this skill.)\n- `rate-limits.json` — Per-provider rate-limit state, keyed by provider name + a SHA-256 digest of the endpoint path. The endpoint itself is not written to this file.\n- `circuit-state.json` — Per-provider circuit-breaker state\n- `fallbacks.json` — Fallback provider mappings\n\nAll of these are intended, documented, and necessary for the skill's features. Default retention is unlimited unless cleared with `--cache --clear` and `--log --clear`.\n\n### Zero External Dependencies\nThis skill uses only Node.js built-ins (`http`, `https`, `fs`, `path`, `os`, `crypto`). There is no `package.json` to install, no transitive dependencies, no `npm install` step. The code you read is the code that runs.\n\n## Quick Start\n\n### Make an API call\n\n```bash\nnode skills/api-gateway/api-gateway.js --call openai https://api.openai.com/v1/chat/completions '{\"model\":\"gpt-4\",\"messages\":[{\"role\":\"user\",\"content\":\"hello\"}]}'\n```\n\nRetries up to 3 times with exponential backoff. Caches response **metadata** for 5 minutes.\n\n### Dry run (preview without executing)\n\n```bash\nnode skills/api-gateway/api-gateway.js --call --dry-run openai https://api.openai.com/v1/chat/completions\n```\n\n### Manage API keys\n\n```bash\n# List configured keys (masked, shows allowlist domains)\nnode skills/api-gateway/api-gateway.js --keys\n\n# Add a key (with provider allowlist)\nnode skills/api-gateway/api-gateway.js --keys add openai sk-abc123 --allow-domain api.openai.com\n\n# Remove a key\nnode skills/api-gateway/api-gateway.js --keys remove openai\n```\n\n### Use environment variables instead of stored keys (recommended for CI/ephemeral)\n\n```bash\nexport OPENAI_API_KEY=sk-abc123\nnode skills/api-gateway/api-gateway.js --call openai https://api.openai.com/v1/chat/completions '{\"model\":\"gpt-4\",\"messages\":[]}'\n```\n\nThe skill auto-detects `PROVIDER_API_KEY` env vars and uses them without disk storage. Stored keys take precedence if both are configured.\n\n### Cache, log, and rate status\n\n```bash\nnode skills/api-gateway/api-gateway.js --cache          # Show cache entries (metadata only)\nnode skills/api-gateway/api-gateway.js --cache --clear  # Clear cache\nnode skills/api-gateway/api-gateway.js --log            # Show request log (coarse: provider, status class, time)\nnode skills/api-gateway/api-gateway.js --log --clear    # Clear request log\nnode skills/api-gateway/api-gateway.js --rate openai    # Rate limit status\n```\n\n### Fallback providers and circuit breaker\n\n```bash\nnode skills/api-gateway/api-gateway.js --fallback openai anthropic\nnode skills/api-gateway/api-gateway.js --circuit --status\nnode skills/api-gateway/api-gateway.js --circuit openai --reset\n```\n\n### Status overview\n\n```bash\nnode skills/api-gateway/api-gateway.js --status\n```\n\n## Provider Allowlist (Security Boundary)\n\nThis is the most important section. The skill uses a **domain allowlist** to decide whether to inject the `Authorization: Bearer` header:\n\n- When you add a key with `--keys add <provider> <key> --allow-domain <domain>`, that domain is stored alongside the key.\n- On every call, the request URL's hostname is extracted and compared against the allowlist (exact match or `*.example.com` wildcard).\n- If the hostname does NOT match, the bearer token is omitted — the request still goes out, just without the key.\n- This means a malicious or mistyped endpoint URL cannot exfiltrate your key.\n\n**Example allowlist configurations:**\n\n```bash\n# Strict: only api.openai.com gets the OpenAI key\n--keys add openai sk-... --allow-domain api.openai.com\n\n# Wildcard: any *.anthropic.com endpoint\n--keys add anthropic sk-ant-... --allow-domain \"*.anthropic.com\"\n\n# Multi-domain (repeat flag)\n--keys add custom TOKEN --allow-domain api.example.com --allow-domain api-staging.example.com\n```\n\nIf you add a key WITHOUT `--allow-domain`, the key is still saved but the skill will **refuse to attach it to any request** until you add at least one allowlist entry. (You can edit `keys.json` to add `allowDomains: [\"api.openai.com\"]` directly.)\n\n## Features\n\n### Retry with Exponential Backoff\n- 3 retry attempts by default\n- Exponential backoff (1s, 2s, 4s)\n- All failures logged with attempt count\n\n### Response Caching (Metadata-Only by Default)\n- 5-minute TTL\n- Cache key = provider name + SHA-256 digest of (endpoint path, request body). The endpoint and body are hashed, never stored — so nothing you send is readable in `cache.json`.\n- Request bodies are hashed with sorted object keys, so logically identical bodies hit the same entry regardless of field order\n- **Default behavior**: caches `{status, headers (redacted), timestamp, bodyLength}`. Body content is NOT stored.\n- **Opt-in full caching**: `--cache-full <provider>` enables full response body caching for that provider.\n- Auto-evicts expired entries\n- Cache hit detection prevents redundant calls\n\n### Rate Limit Handling\n- Tracks remaining requests from `x-ratelimit-remaining` headers\n- Auto-fallback when rate limited (if configured)\n- Status check via `--rate`\n\n### Key Management\n- Masked display (first 4 + last 4 chars)\n- Per-provider key storage in `memory/api-gateway/keys.json`\n- **chmod 0600** on the file (POSIX only; best-effort on Windows)\n- Environment-variable auto-detection (PROVIDER_API_KEY)\n- Allowlist attached to each key\n- Add/remove keys without exposing full values\n\n### Fallback Providers\n- Configurable per-provider fallback chain\n- Automatic failover on rate limit or error\n- No manual intervention needed\n\n### Circuit Breaker\n- Tracks failure rates per provider\n- Opens circuit after 5 consecutive failures\n- Auto-recovers after 30s cooldown (HALF-OPEN state)\n- Prevents cascading failures and saves API costs\n- CLI visibility: `--circuit --status` + `--circuit <name> --reset`\n\n## Configuration\n\nData files stored in: `memory/api-gateway/`\n\n- `keys.json` — API key storage (chmod 0600)\n- `fallbacks.json` — Fallback provider mappings\n- `cache.json` — Response cache (metadata-only by default)\n- `rate-limits.json` — Rate limit tracking\n- `request-log.json` — Request history (coarse: provider, status class, timestamp, NOT endpoints)\n- `circuit-state.json` — Circuit breaker state per provider\n\nOverride data directory:\n```bash\n--dir /path/to/data\n# or env var\nAPI_GATEWAY_DIR=/path/to/data node api-gateway.js --status\n```\n\n## Agent Protocol\n\nWhen making API calls:\n\n1. **Use the gateway** — `--call <provider> <endpoint> [body]` instead of direct fetch\n2. **Add keys with allowlist** — `--keys add <provider> <key> --allow-domain <domain>` before first use\n- **Prefer env vars in CI** — `PROVIDER_API_KEY` env vars bypass disk storage entirely. API Gateway auto-detects any `PROVIDER_API_KEY` environment variable (e.g. `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`) and uses it without disk storage. It does NOT read arbitrary environment variables — only the documented `PROVIDER_API_KEY` pattern — so unrelated secrets are never exposed to requests or local processing.\n4. **Set fallbacks** — `--fallback primary secondary` for critical providers\n5. **Check cache/log** — `--cache` / `--log` during heartbeats to monitor usage\n6. **Dry run** — `--call --dry-run` before executing important calls\n\n## Security Notes\n- Keys stored as plain text in JSON with chmod 0600 (POSIX)\n- For higher assurance, use environment variables (`PROVIDER_API_KEY`)\n- For production, integrate with a secrets manager\n- Masked output prevents accidental exposure in logs\n- Request log stores only provider + status class + timestamp (no endpoints)\n- Allowlist is a strict domain match, not a string contains\n- Code has zero external dependencies (no npm install)\n- ⚠️ **DATA LEAVES TO A THIRD PARTY:** every `--call` sends your request (URL, headers, body, prompts) to the provider endpoint YOU specify — a separate external service. Responses come back from that provider and may be retained by them per their own policy. This skill is NOT a transparent pass-through; it centralizes collection, storage, and forwarding of potentially sensitive data. Only call endpoints you trust.\n- ⚠️ **SENSITIVE DATA IN LOGS/CACHE (default vs opt-in):**\n  - The **request log** stores only provider name + status class + timestamp. It does NOT store endpoint URLs, query strings, or request/response bodies. (If you put a secret in a request body, that body goes to the provider but is never written to the request log.)\n  - **`cache.json` is metadata-only by default** (status, timestamp, response headers, body *length*). The full response **body** is written to disk ONLY when you explicitly enable `--cache-full <provider>`.\n  - **Cache and rate-limit keys are hashed, not stored.** The key is the provider name plus a SHA-256 digest of the endpoint path and request body. Your prompts, payloads, and endpoint URLs are therefore not recoverable from `cache.json` or `rate-limits.json`. (Prior to v1.1.10 these keys embedded the endpoint and the full request body in plaintext; v1.1.10 purges any such legacy entries from disk the first time it loads them.)\n  - So by default, endpoints/bodies you pass are NOT persisted locally in readable form by this skill. The only local exposure path is `--cache-full`, which stores complete responses. Clear caches after sensitive work (`--log --clear`, `--cache --clear`) and never use `--cache-full` for sensitive providers.\n- ⚠️ **FULL-BODY CACHING WRITES COMPLETE RESPONSES TO DISK:** `--cache-full <provider>` stores the ENTIRE response body (which may contain secrets, tokens, personal data, or proprietary content) in `cache.json`. This is a local data-exposure risk if the host/workspace is shared or later exfiltrated. Never use `--cache-full` with sensitive providers; prefer the default metadata-only cache.\n- ⚠️ **HTTPS ONLY:** API Gateway refuses to send any request over plain HTTP (it would expose bearer credentials on the wire). Set `API_GATEWAY_ALLOW_HTTP=1` only for non-credential plaintext endpoints.\n\n## What This Skill Does NOT Do\n\n- Does NOT install npm packages\n- Does NOT auto-update or phone home\n- Does NOT read environment variables silently — only the documented `PROVIDER_API_KEY` pattern\n- Does NOT send Authorization headers to URLs outside the allowlist\n- Does NOT cache full response bodies unless explicitly opted in per provider\n- Does NOT write request bodies or endpoint URLs to disk — cache and rate-limit keys are SHA-256 digests\n- Does NOT log full endpoint URLs or query strings\n\n## Design Principles\n\n1. **Zero setup** — Works immediately, no config needed\n2. **No dependencies** — Pure Node.js http/https, no npm packages\n3. **Resilient** — Retry, fallback, and rate limit handling built in\n4. **Transparent** — Masked keys, cache status, request logging\n5. **Composable** — Works with any HTTP API, not just specific providers\n6. **Fail-closed on security boundaries** — If the allowlist doesn't match, the key is not sent. If a file permission can't be set, the call still proceeds but a warning is logged.\n\nFile v1.1.12:README.md\n\n# API Gateway\n\nSmart proxy for external API calls with retry logic, caching, circuit breaker, and rate limiting.\n\n> ⚠️ **DATA LEAVES TO A THIRD PARTY:** every `--call` sends your request (URL, headers, body, prompts) to the provider endpoint *you* specify — a separate external service. Responses come back from that provider and may be retained by them per their own policy. This skill is NOT a transparent pass-through; it centralizes collection, storage, and forwarding of potentially sensitive data. Only call endpoints you trust. By default only request **metadata** (provider, status class, timestamp) and cache **metadata** are written to disk; the full response body is written only if you enable `--cache-full <provider>`. Cache and rate-limit entries are keyed by a SHA-256 digest of the endpoint path and request body, so neither your endpoints nor your payloads are stored on disk in readable form.\n\n## Features\n\n- **HTTP Proxy** — Make API calls with automatic retry and timeout handling\n- **Circuit Breaker** — Automatic failure detection and cooldown (opens after 5 failures)\n- **Response Caching** — Cache API responses to reduce repeated calls\n- **Rate Limiting** — Per-provider rate limit tracking\n- **Fallback Providers** — Configure fallback providers for redundancy\n- **API Key Management** — Store, list, and remove API keys with masked output\n- **Request Logging** — Track request history for debugging\n\n## Installation\n\n```bash\n# The skill is auto-loaded by OpenClaw via the skill registry.\n# For standalone use:\nconst AG = require('./api-gateway.js');\n```\n\n## Commands\n\n```\n--call <provider> <endpoint> [body]       Make API call with retry/caching\n--call --dry-run <provider> <endpoint>    Preview call without executing\n--keys                                     List configured API keys (masked)\n--keys add <provider> <key>               Add API key\n--keys remove <provider>                  Remove API key\n--cache                                    Show cache status\n--cache --clear                            Clear cache\n--rate <provider>                          Check rate limit status\n--fallback <provider> <fallback>           Set fallback provider\n--status                                   Gateway status overview\n```\n\n## API\n\n### `makeRequest(url, method, headers, body, timeout)`\nMake an HTTP request with automatic retry and timeout.\n\n```javascript\nconst result = await AG.makeRequest('https://api.openai.com/v1/models', 'GET', {}, null, 30000);\n```\n\n### `maskKey(key)`\nMask a sensitive key for display (`sk-a****fgh`).\n\n### Circuit Breaker\n```javascript\nAG.getCircuitState('openai');     // Current state (CLOSED/OPEN/HALF-OPEN)\nAG.recordFailure('openai');       // Record a failure\nAG.recordSuccess('openai');       // Record a success (resets counter)\nAG.getCircuitStatus();            // All circuit states\nAG.resetCircuit('openai');        // Reset circuit breaker\n```\n\n### Key Management\n```javascript\nAG.addKey('openai', 'sk-...');    // Add API key\nAG.removeKey('openai');           // Remove API key\nAG.listKeys();                    // List all keys (masked)\n```\n\n### Cache\n```javascript\nAG.showCache();                   // Show cached responses\nAG.clearCache();                  // Clear all cached responses\n```\n\n### Fallback\n```javascript\nAG.setFallback('openai', 'anthropic');  // Set fallback provider\nAG.listFallbacks();                     // List all fallback providers\n```\n\n### Status\n```javascript\nAG.showStatus();                  // Full gateway status\n```\n\n## Security\n\n- API keys masked by default in console output\n- Circuit breaker prevents rapid retry cascades\n- Backoff strategy: 1s → 2s → 4s → 8s → 16s (exponential)\n- Max 5 retries per request\n- Cache expires after configurable TTL\n- Cache keys are provider name + SHA-256 digest of (endpoint path, request body) — nothing you send is stored in plaintext\n\n## Testing\n\n```bash\nnode tests/run-self-tests.js\n```\n\n### Test Coverage\n\n| Suite | Tests | Status |\n|---|---|---|\n| Self-tests (isolated) | 20 | ✅ Passing |\n\nFile v1.1.12:_meta.json\n\n{\n  \"ownerId\": \"kn7b6eyf5vc7khg5fr63pjm8xd82qvw5\",\n  \"slug\": \"api-proxy\",\n  \"version\": \"1.1.12\",\n  \"publishedAt\": 1789302891177\n}\n\nFile v1.1.12:skill-card.md\n\n## Description:\n\nAPI Gateway is a local Node.js proxy for outbound API calls with retries, metadata-only caching by default, rate-limit handling, circuit breaking, fallback providers, and API key management.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[jlacroix82](https://clawhub.ai/user/jlacroix82)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and agents use this skill to centralize outbound HTTP API calls through a reusable gateway with retry, fallback, rate-limit, cache, request-log, and API-key handling controls.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The gateway handles provider credentials and can store API keys as plaintext in the local workspace.\n\nMitigation: Prefer PROVIDER_API_KEY environment variables or a secrets manager, use tightly scoped allowlisted stored keys only when needed, and remove local keys after sensitive work.\n\nRisk: Requests, prompts, headers, bodies, and responses are transmitted to the third-party provider endpoint selected by the caller.\n\nMitigation: Send requests only to trusted endpoints, review provider retention policies, and avoid routing sensitive or regulated data through untrusted providers.\n\nRisk: Full-body caching can persist complete responses that may contain secrets, personal data, or proprietary content.\n\nMitigation: Keep the default metadata-only cache, avoid --cache-full for sensitive providers, and clear cache and log files after sensitive sessions.\n\nRisk: Plain HTTP can expose traffic when API_GATEWAY_ALLOW_HTTP=1 is enabled.\n\nMitigation: Use HTTPS endpoints and never enable API_GATEWAY_ALLOW_HTTP=1 when credentials or sensitive payloads may be attached.\n\n## Reference(s):\n\n- [ClawHub skill page](https://clawhub.ai/jlacroix82/skills/api-proxy)\n- [README](README.md)\n- [Vetting report](VET-REPORT.md)\n\n## Skill Output:\n\n**Output Type(s):** [text, shell commands, configuration, guidance]\n\n**Output Format:** [CLI text, JSON API responses, and Markdown guidance]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [May perform outbound HTTP API calls and write local gateway state, including keys, cache metadata, request logs, rate-limit state, circuit state, and fallback mappings.]\n\n## Skill Version(s):\n\n1.1.12 (source: frontmatter and server release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nFile v1.1.12:VET-REPORT.md\n\n# Vetting Report: api-proxy\n**Date:** 2026-09-13 08:11 EDT\n**Vetter:** JARVIS (skill-vetter skill)\n**Source:** local (/home/jarvis/.openclaw/workspace)\n**Verdict:** PASS\n**Risk score:** 8/100\n\n## Findings\n\n### Critical\n- (none)\n\n### Warnings\n- 2 network URLs\n- No description in frontmatter\n\n### Notes\n- (none)\n\n## Permission footprint\n- Tools requested: exec process read write \n\n## Network footprint\nhttps://api.openai.com/v1/chat/completion\nhttps://attacker.com/api?provider=openai` will NOT receive the key becau\n\n## Side effects\n- Reads: SKILL.md\n- Writes: VET-REPORT.md (this file)\n- Network: 2 distinct hosts\n\n## Verdict rationale\nScore 8/100 with 0 critical findings and 2 warnings.\n\nFile v1.1.12:clawhub.yaml\n\nslug: api-proxy\nname: api-gateway\nowner: jlacroix82\ndescription: Smart proxy for external API calls with retry, caching, circuit breaker, and rate limiting. PERSISTS: API keys (chmod 0600 plaintext in keys.json), request/response cache metadata, and request logs. Network: outbound HTTPS only, with a strict provider-domain allowlist. Caches metadata by default; full response bodies are opt-in per provider. Cache and rate-limit keys are SHA-256 digests, so request bodies and endpoint URLs are never persisted in plaintext. WARNING: Requests transmit prompts, request bodies, headers, and responses to third-party API providers. Keys apply allowlist to all sources (env-var or disk-stored).\nversion: 1.1.12\ntype: skill\nauthor: OpenClaw\nlicense: MIT\nkeywords:\n  - api\n  - proxy\n  - gateway\n  - circuit-breaker\n  - caching\n  - rate-limit\n  - allowlist\n  - security\ncapabilities:\n  - network\n  - filesystem\n  - environment\nentry: SKILL.md\ndependencies: []\npermissions:\n  - name: network.outbound\n    description: Outbound HTTPS to provider allowlist domains\n  - name: filesystem.read-write\n    description: Read/write data files in memory/api-gateway/ (keys.json chmod 0600)\n  - name: environment.read\n    description: Read PROVIDER_API_KEY environment variables\ndata_retention:\n  cache: 'metadata-only by default; full body opt-in per provider. Keys are provider name + SHA-256 digest of endpoint path and request body — neither is stored in plaintext'\n  rate_limits: 'per-provider counters keyed by provider name + SHA-256 digest of the endpoint path — the endpoint is not stored'\n  log: 'coarse: provider, status class, timestamp only — no endpoint paths or query strings stored'\n  keys: 'plaintext on disk with chmod 0600; env var override supported'\nsecurity_notes:\n  - 'WARNING: Requests transmit prompts, request bodies, headers, and responses to third-party API providers. Do not route sensitive/regulated data through the gateway.'\n  - 'Allowlist enforced for ALL keys (env-var and disk-stored) — both refuse auth if hostname not in allowlist'\n  - 'Keys stored as plain text in JSON with chmod 0600 (POSIX)'\n  - 'Request log stores only provider, status class, timestamp — no endpoint paths or query strings'\n  - 'Cache and rate-limit keys are SHA-256 digests: request bodies and endpoint URLs are never written to disk in plaintext. Legacy plaintext entries from <= 1.1.9 are purged on first load'\n  - 'For production, integrate with a secrets manager for API key storage'\n  - 'Use --call --dry-run before executing important calls'\n  - 'Clear logs/cache for sensitive work: --log --clear and --cache --clear'\n  - 'Masked output prevents accidental exposure in logs'\n\nArchive v1.1.11: 8 files, 23363 bytes\n\nFiles: api-gateway.js (35648b), clawhub.yaml (2685b), README.md (4066b), skill-card.md (2168b), SKILL.md (14388b), test/run-tests.js (3485b), tests/run-self-tests.js (6632b), _meta.json (129b)\n\nFile v1.1.11:SKILL.md\n\n---\nname: api-gateway\ndescription: Smart proxy for external API calls with retry, caching, rate limiting, and fallback providers. PERSISTS: API keys (chmod 0600 plaintext in keys.json), request/response cache metadata, and request logs. Network: outbound HTTPS only, with a strict provider-domain allowlist. Caches metadata by default; full response bodies are opt-in per provider. Cache and rate-limit keys are SHA-256 digests, so request bodies and endpoint URLs are never written to disk in plaintext.\n---\n\n# API Gateway ⚡\n\n> **Read this first.** This skill makes outbound HTTPS calls and writes plaintext API keys to disk. By installing or running it, you accept responsibility for the security of the keys you provide and the endpoints you target.\n\n**Stop duplicating API logic. Start routing through one smart gateway.**\n\n## What This Skill Does\n\nAPI Gateway is a local Node.js HTTP client wrapper that gives one call:\n\n- **Retry with exponential backoff** (3 attempts, 1s/2s/4s)\n- **Response caching** (default 5 min TTL, metadata-only)\n- **Rate-limit handling** (parses `x-ratelimit-remaining`, auto-fallback)\n- **Circuit breaker** (5-failure open, 30s cooldown, auto-recover)\n- **API key management** (masked display, chmod 0600 storage, env-var override)\n- **Fallback providers** (configurable per-provider chain)\n\n## ⚠️ Important Warnings\n\n### Outbound HTTPS Requests to Whitelisted Provider Domains\n`--call <provider> <endpoint>` sends HTTPS requests and, for configured providers, attaches a `Authorization: Bearer <key>` header. **The provider allowlist is strict: it is a domain-match check, not a `string.includes()` check.** A URL like `https://attacker.com/api?provider=openai` will NOT receive the key because the hostname must match the provider's registered allowlist entry. Review the allowlist in `--keys` output before adding sensitive keys.\n\n### API Keys Stored in Plaintext on Disk\nAPI keys saved via `--keys add` are written to `memory/api-gateway/keys.json` in plaintext, with file permissions set to `0600` (owner read/write only). The key is NEVER echoed back. Anyone with shell access to the workspace as the same user can still read it. For higher assurance, prefer environment variables: `OPENAI_API_KEY=sk-...` — API Gateway auto-detects any `PROVIDER_API_KEY` variable (e.g. `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`) and uses it without disk storage. It does NOT read arbitrary `env:NAME` references — only the `PROVIDER_API_KEY` pattern — so unrelated secrets are never pulled in.\n\n### Persistent Data Files (Disclosed Up Front)\nThe following files persist in `memory/api-gateway/` after any operation:\n- `keys.json` — API key storage, chmod 0600\n- `cache.json` — **Metadata-only by default** (status code, timestamp, response headers, response body *length*). The full response **body** is NOT stored unless you explicitly enable it per provider via `--cache-full <provider>`. **Cache keys are provider name + a SHA-256 digest of the endpoint path and request body** — the endpoint and the body themselves are never written to this file.\n- `request-log.json` — Provider name, status class (2xx/4xx/5xx), timestamp. Endpoint URLs, query strings, and request/response **bodies are NOT written here.** (Note: if *you* pass a URL or prompt inside a request body to `--call`, that body travels to the provider but is never persisted to the log or cache by this skill.)\n- `rate-limits.json` — Per-provider rate-limit state, keyed by provider name + a SHA-256 digest of the endpoint path. The endpoint itself is not written to this file.\n- `circuit-state.json` — Per-provider circuit-breaker state\n- `fallbacks.json` — Fallback provider mappings\n\nAll of these are intended, documented, and necessary for the skill's features. Default retention is unlimited unless cleared with `--cache --clear` and `--log --clear`.\n\n### Zero External Dependencies\nThis skill uses only Node.js built-ins (`http`, `https`, `fs`, `path`, `os`, `crypto`). There is no `package.json` to install, no transitive dependencies, no `npm install` step. The code you read is the code that runs.\n\n## Quick Start\n\n### Make an API call\n\n```bash\nnode skills/api-gateway/api-gateway.js --call openai https://api.openai.com/v1/chat/completions '{\"model\":\"gpt-4\",\"messages\":[{\"role\":\"user\",\"content\":\"hello\"}]}'\n```\n\nRetries up to 3 times with exponential backoff. Caches response **metadata** for 5 minutes.\n\n### Dry run (preview without executing)\n\n```bash\nnode skills/api-gateway/api-gateway.js --call --dry-run openai https://api.openai.com/v1/chat/completions\n```\n\n### Manage API keys\n\n```bash\n# List configured keys (masked, shows allowlist domains)\nnode skills/api-gateway/api-gateway.js --keys\n\n# Add a key (with provider allowlist)\nnode skills/api-gateway/api-gateway.js --keys add openai sk-abc123 --allow-domain api.openai.com\n\n# Remove a key\nnode skills/api-gateway/api-gateway.js --keys remove openai\n```\n\n### Use environment variables instead of stored keys (recommended for CI/ephemeral)\n\n```bash\nexport OPENAI_API_KEY=sk-abc123\nnode skills/api-gateway/api-gateway.js --call openai https://api.openai.com/v1/chat/completions '{\"model\":\"gpt-4\",\"messages\":[]}'\n```\n\nThe skill auto-detects `PROVIDER_API_KEY` env vars and uses them without disk storage. Stored keys take precedence if both are configured.\n\n### Cache, log, and rate status\n\n```bash\nnode skills/api-gateway/api-gateway.js --cache          # Show cache entries (metadata only)\nnode skills/api-gateway/api-gateway.js --cache --clear  # Clear cache\nnode skills/api-gateway/api-gateway.js --log            # Show request log (coarse: provider, status class, time)\nnode skills/api-gateway/api-gateway.js --log --clear    # Clear request log\nnode skills/api-gateway/api-gateway.js --rate openai    # Rate limit status\n```\n\n### Fallback providers and circuit breaker\n\n```bash\nnode skills/api-gateway/api-gateway.js --fallback openai anthropic\nnode skills/api-gateway/api-gateway.js --circuit --status\nnode skills/api-gateway/api-gateway.js --circuit openai --reset\n```\n\n### Status overview\n\n```bash\nnode skills/api-gateway/api-gateway.js --status\n```\n\n## Provider Allowlist (Security Boundary)\n\nThis is the most important section. The skill uses a **domain allowlist** to decide whether to inject the `Authorization: Bearer` header:\n\n- When you add a key with `--keys add <provider> <key> --allow-domain <domain>`, that domain is stored alongside the key.\n- On every call, the request URL's hostname is extracted and compared against the allowlist (exact match or `*.example.com` wildcard).\n- If the hostname does NOT match, the bearer token is omitted — the request still goes out, just without the key.\n- This means a malicious or mistyped endpoint URL cannot exfiltrate your key.\n\n**Example allowlist configurations:**\n\n```bash\n# Strict: only api.openai.com gets the OpenAI key\n--keys add openai sk-... --allow-domain api.openai.com\n\n# Wildcard: any *.anthropic.com endpoint\n--keys add anthropic sk-ant-... --allow-domain \"*.anthropic.com\"\n\n# Multi-domain (repeat flag)\n--keys add custom TOKEN --allow-domain api.example.com --allow-domain api-staging.example.com\n```\n\nIf you add a key WITHOUT `--allow-domain`, the key is still saved but the skill will **refuse to attach it to any request** until you add at least one allowlist entry. (You can edit `keys.json` to add `allowDomains: [\"api.openai.com\"]` directly.)\n\n## Features\n\n### Retry with Exponential Backoff\n- 3 retry attempts by default\n- Exponential backoff (1s, 2s, 4s)\n- All failures logged with attempt count\n\n### Response Caching (Metadata-Only by Default)\n- 5-minute TTL\n- Cache key = provider name + SHA-256 digest of (endpoint path, request body). The endpoint and body are hashed, never stored — so nothing you send is readable in `cache.json`.\n- Request bodies are hashed with sorted object keys, so logically identical bodies hit the same entry regardless of field order\n- **Default behavior**: caches `{status, headers (redacted), timestamp, bodyLength}`. Body content is NOT stored.\n- **Opt-in full caching**: `--cache-full <provider>` enables full response body caching for that provider.\n- Auto-evicts expired entries\n- Cache hit detection prevents redundant calls\n\n### Rate Limit Handling\n- Tracks remaining requests from `x-ratelimit-remaining` headers\n- Auto-fallback when rate limited (if configured)\n- Status check via `--rate`\n\n### Key Management\n- Masked display (first 4 + last 4 chars)\n- Per-provider key storage in `memory/api-gateway/keys.json`\n- **chmod 0600** on the file (POSIX only; best-effort on Windows)\n- Environment-variable auto-detection (PROVIDER_API_KEY)\n- Allowlist attached to each key\n- Add/remove keys without exposing full values\n\n### Fallback Providers\n- Configurable per-provider fallback chain\n- Automatic failover on rate limit or error\n- No manual intervention needed\n\n### Circuit Breaker\n- Tracks failure rates per provider\n- Opens circuit after 5 consecutive failures\n- Auto-recovers after 30s cooldown (HALF-OPEN state)\n- Prevents cascading failures and saves API costs\n- CLI visibility: `--circuit --status` + `--circuit <name> --reset`\n\n## Configuration\n\nData files stored in: `memory/api-gateway/`\n\n- `keys.json` — API key storage (chmod 0600)\n- `fallbacks.json` — Fallback provider mappings\n- `cache.json` — Response cache (metadata-only by default)\n- `rate-limits.json` — Rate limit tracking\n- `request-log.json` — Request history (coarse: provider, status class, timestamp, NOT endpoints)\n- `circuit-state.json` — Circuit breaker state per provider\n\nOverride data directory:\n```bash\n--dir /path/to/data\n# or env var\nAPI_GATEWAY_DIR=/path/to/data node api-gateway.js --status\n```\n\n## Agent Protocol\n\nWhen making API calls:\n\n1. **Use the gateway** — `--call <provider> <endpoint> [body]` instead of direct fetch\n2. **Add keys with allowlist** — `--keys add <provider> <key> --allow-domain <domain>` before first use\n- **Prefer env vars in CI** — `PROVIDER_API_KEY` env vars bypass disk storage entirely. API Gateway auto-detects any `PROVIDER_API_KEY` environment variable (e.g. `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`) and uses it without disk storage. It does NOT read arbitrary environment variables — only the documented `PROVIDER_API_KEY` pattern — so unrelated secrets are never exposed to requests or local processing.\n4. **Set fallbacks** — `--fallback primary secondary` for critical providers\n5. **Check cache/log** — `--cache` / `--log` during heartbeats to monitor usage\n6. **Dry run** — `--call --dry-run` before executing important calls\n\n## Security Notes\n- Keys stored as plain text in JSON with chmod 0600 (POSIX)\n- For higher assurance, use environment variables (`PROVIDER_API_KEY`)\n- For production, integrate with a secrets manager\n- Masked output prevents accidental exposure in logs\n- Request log stores only provider + status class + timestamp (no endpoints)\n- Allowlist is a strict domain match, not a string contains\n- Code has zero external dependencies (no npm install)\n- ⚠️ **DATA LEAVES TO A THIRD PARTY:** every `--call` sends your request (URL, headers, body, prompts) to the provider endpoint YOU specify — a separate external service. Responses come back from that provider and may be retained by them per their own policy. This skill is NOT a transparent pass-through; it centralizes collection, storage, and forwarding of potentially sensitive data. Only call endpoints you trust.\n- ⚠️ **SENSITIVE DATA IN LOGS/CACHE (default vs opt-in):**\n  - The **request log** stores only provider name + status class + timestamp. It does NOT store endpoint URLs, query strings, or request/response bodies. (If you put a secret in a request body, that body goes to the provider but is never written to the request log.)\n  - **`cache.json` is metadata-only by default** (status, timestamp, response headers, body *length*). The full response **body** is written to disk ONLY when you explicitly enable `--cache-full <provider>`.\n  - **Cache and rate-limit keys are hashed, not stored.** The key is the provider name plus a SHA-256 digest of the endpoint path and request body. Your prompts, payloads, and endpoint URLs are therefore not recoverable from `cache.json` or `rate-limits.json`. (Prior to v1.1.10 these keys embedded the endpoint and the full request body in plaintext; v1.1.10 purges any such legacy entries from disk the first time it loads them.)\n  - So by default, endpoints/bodies you pass are NOT persisted locally in readable form by this skill. The only local exposure path is `--cache-full`, which stores complete responses. Clear caches after sensitive work (`--log --clear`, `--cache --clear`) and never use `--cache-full` for sensitive providers.\n- ⚠️ **FULL-BODY CACHING WRITES COMPLETE RESPONSES TO DISK:** `--cache-full <provider>` stores the ENTIRE response body (which may contain secrets, tokens, personal data, or proprietary content) in `cache.json`. This is a local data-exposure risk if the host/workspace is shared or later exfiltrated. Never use `--cache-full` with sensitive providers; prefer the default metadata-only cache.\n- ⚠️ **HTTPS ONLY:** API Gateway refuses to send any request over plain HTTP (it would expose bearer credentials on the wire). Set `API_GATEWAY_ALLOW_HTTP=1` only for non-credential plaintext endpoints.\n\n## What This Skill Does NOT Do\n\n- Does NOT install npm packages\n- Does NOT auto-update or phone home\n- Does NOT read environment variables silently — only the documented `PROVIDER_API_KEY` pattern\n- Does NOT send Authorization headers to URLs outside the allowlist\n- Does NOT cache full response bodies unless explicitly opted in per provider\n- Does NOT write request bodies or endpoint URLs to disk — cache and rate-limit keys are SHA-256 digests\n- Does NOT log full endpoint URLs or query strings\n\n## Design Principles\n\n1. **Zero setup** — Works immediately, no config needed\n2. **No dependencies** — Pure Node.js http/https, no npm packages\n3. **Resilient** — Retry, fallback, and rate limit handling built in\n4. **Transparent** — Masked keys, cache status, request logging\n5. **Composable** — Works with any HTTP API, not just specific providers\n6. **Fail-closed on security boundaries** — If the allowlist doesn't match, the key is not sent. If a file permission can't be set, the call still proceeds but a warning is logged.\n\nFile v1.1.11:README.md\n\n# API Gateway\n\nSmart proxy for external API calls with retry logic, caching, circuit breaker, and rate limiting.\n\n> ⚠️ **DATA LEAVES TO A THIRD PARTY:** every `--call` sends your request (URL, headers, body, prompts) to the provider endpoint *you* specify — a separate external service. Responses come back from that provider and may be retained by them per their own policy. This skill is NOT a transparent pass-through; it centralizes collection, storage, and forwarding of potentially sensitive data. Only call endpoints you trust. By default only request **metadata** (provider, status class, timestamp) and cache **metadata** are written to disk; the full response body is written only if you enable `--cache-full <provider>`. Cache and rate-limit entries are keyed by a SHA-256 digest of the endpoint path and request body, so neither your endpoints nor your payloads are stored on disk in readable form.\n\n## Features\n\n- **HTTP Proxy** — Make API calls with automatic retry and timeout handling\n- **Circuit Breaker** — Automatic failure detection and cooldown (opens after 5 failures)\n- **Response Caching** — Cache API responses to reduce repeated calls\n- **Rate Limiting** — Per-provider rate limit tracking\n- **Fallback Providers** — Configure fallback providers for redundancy\n- **API Key Management** — Store, list, and remove API keys with masked output\n- **Request Logging** — Track request history for debugging\n\n## Installation\n\n```bash\n# The skill is auto-loaded by OpenClaw via the skill registry.\n# For standalone use:\nconst AG = require('./api-gateway.js');\n```\n\n## Commands\n\n```\n--call <provider> <endpoint> [body]       Make API call with retry/caching\n--call --dry-run <provider> <endpoint>    Preview call without executing\n--keys                                     List configured API keys (masked)\n--keys add <provider> <key>               Add API key\n--keys remove <provider>                  Remove API key\n--cache                                    Show cache status\n--cache --clear                            Clear cache\n--rate <provider>                          Check rate limit status\n--fallback <provider> <fallback>           Set fallback provider\n--status                                   Gateway status overview\n```\n\n## API\n\n### `makeRequest(url, method, headers, body, timeout)`\nMake an HTTP request with automatic retry and timeout.\n\n```javascript\nconst result = await AG.makeRequest('https://api.openai.com/v1/models', 'GET', {}, null, 30000);\n```\n\n### `maskKey(key)`\nMask a sensitive key for display (`sk-a****fgh`).\n\n### Circuit Breaker\n```javascript\nAG.getCircuitState('openai');     // Current state (CLOSED/OPEN/HALF-OPEN)\nAG.recordFailure('openai');       // Record a failure\nAG.recordSuccess('openai');       // Record a success (resets counter)\nAG.getCircuitStatus();            // All circuit states\nAG.resetCircuit('openai');        // Reset circuit breaker\n```\n\n### Key Management\n```javascript\nAG.addKey('openai', 'sk-...');    // Add API key\nAG.removeKey('openai');           // Remove API key\nAG.listKeys();                    // List all keys (masked)\n```\n\n### Cache\n```javascript\nAG.showCache();                   // Show cached responses\nAG.clearCache();                  // Clear all cached responses\n```\n\n### Fallback\n```javascript\nAG.setFallback('openai', 'anthropic');  // Set fallback provider\nAG.listFallbacks();                     // List all fallback providers\n```\n\n### Status\n```javascript\nAG.showStatus();                  // Full gateway status\n```\n\n## Security\n\n- API keys masked by default in console output\n- Circuit breaker prevents rapid retry cascades\n- Backoff strategy: 1s → 2s → 4s → 8s → 16s (exponential)\n- Max 5 retries per request\n- Cache expires after configurable TTL\n- Cache keys are provider name + SHA-256 digest of (endpoint path, request body) — nothing you send is stored in plaintext\n\n## Testing\n\n```bash\nnode tests/run-self-tests.js\n```\n\n### Test Coverage\n\n| Suite | Tests | Status |\n|---|---|---|\n| Self-tests (isolated) | 20 | ✅ Passing |\n\nFile v1.1.11:_meta.json\n\n{\n  \"ownerId\": \"kn7b6eyf5vc7khg5fr63pjm8xd82qvw5\",\n  \"slug\": \"api-proxy\",\n  \"version\": \"1.1.11\",\n  \"publishedAt\": 1786824518602\n}\n\nFile v1.1.11:skill-card.md\n\n## Description:\n\nAPI Gateway is a local proxy for external API calls with retry handling, metadata-only caching by default, rate-limit tracking, circuit breaking, fallback providers, and disclosed key-storage controls.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[jlacroix82](https://clawhub.ai/user/jlacroix82)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and agents use this skill to centralize outbound API calls through one local gateway with retries, caching controls, rate-limit awareness, fallback routing, and masked API-key management.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Outbound calls send request URLs, headers, bodies, prompts, and responses to the provider endpoint selected by the user.\n\nMitigation: Install only when a local API gateway is desired, call only trusted endpoints, and use provider allowlists carefully.\n\nRisk: API keys stored with the skill are plaintext on disk, even with chmod 0600 permissions.\n\nMitigation: Prefer environment variables or a secrets manager for sensitive keys, especially in shared, production, or CI environments.\n\nRisk: Full-body caching can write complete provider responses to disk when explicitly enabled.\n\nMitigation: Avoid --cache-full for sensitive responses and clear logs or cache after sensitive work.\n\n## Reference(s):\n\n- [ClawHub skill page](https://clawhub.ai/jlacroix82/skills/api-proxy)\n\n## Skill Output:\n\n**Output Type(s):** [Guidance, Shell commands, Configuration, Code]\n\n**Output Format:** [Markdown with inline shell commands and JavaScript examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Produces local gateway commands and configuration guidance; runtime calls may create JSON data files under memory/api-gateway.]\n\n## Skill Version(s):\n\n1.1.11 (source: server release evidence and artifact clawhub.yaml)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nFile v1.1.11:clawhub.yaml\n\nslug: api-proxy\nname: api-gateway\nowner: jlacroix82\ndescription: Smart proxy for external API calls with retry, caching, circuit breaker, and rate limiting. PERSISTS: API keys (chmod 0600 plaintext in keys.json), request/response cache metadata, and request logs. Network: outbound HTTPS only, with a strict provider-domain allowlist. Caches metadata by default; full response bodies are opt-in per provider. Cache and rate-limit keys are SHA-256 digests, so request bodies and endpoint URLs are never persisted in plaintext. WARNING: Requests transmit prompts, request bodies, headers, and responses to third-party API providers. Keys apply allowlist to all sources (env-var or disk-stored).\nversion: 1.1.11\ntype: skill\nauthor: OpenClaw\nlicense: MIT\nkeywords:\n  - api\n  - proxy\n  - gateway\n  - circuit-breaker\n  - caching\n  - rate-limit\n  - allowlist\n  - security\ncapabilities:\n  - network\n  - filesystem\n  - environment\nentry: SKILL.md\ndependencies: []\npermissions:\n  - name: network.outbound\n    description: Outbound HTTPS to provider allowlist domains\n  - name: filesystem.read-write\n    description: Read/write data files in memory/api-gateway/ (keys.json chmod 0600)\n  - name: environment.read\n    description: Read PROVIDER_API_KEY environment variables\ndata_retention:\n  cache: 'metadata-only by default; full body opt-in per provider. Keys are provider name + SHA-256 digest of endpoint path and request body — neither is stored in plaintext'\n  rate_limits: 'per-provider counters keyed by provider name + SHA-256 digest of the endpoint path — the endpoint is not stored'\n  log: 'coarse: provider, status class, timestamp only — no endpoint paths or query strings stored'\n  keys: 'plaintext on disk with chmod 0600; env var override supported'\nsecurity_notes:\n  - 'WARNING: Requests transmit prompts, request bodies, headers, and responses to third-party API providers. Do not route sensitive/regulated data through the gateway.'\n  - 'Allowlist enforced for ALL keys (env-var and disk-stored) — both refuse auth if hostname not in allowlist'\n  - 'Keys stored as plain text in JSON with chmod 0600 (POSIX)'\n  - 'Request log stores only provider, status class, timestamp — no endpoint paths or query strings'\n  - 'Cache and rate-limit keys are SHA-256 digests: request bodies and endpoint URLs are never written to disk in plaintext. Legacy plaintext entries from <= 1.1.9 are purged on first load'\n  - 'For production, integrate with a secrets manager for API key storage'\n  - 'Use --call --dry-run before executing important calls'\n  - 'Clear logs/cache for sensitive work: --log --clear and --cache --clear'\n  - 'Masked output prevents accidental exposure in logs'\n\nArchive v1.1.9: 8 files, 21562 bytes\n\nFiles: api-gateway.js (32645b), clawhub.yaml (2136b), README.md (3762b), skill-card.md (2258b), SKILL.md (13155b), test/run-tests.js (3485b), tests/run-self-tests.js (6632b), _meta.json (128b)\n\nFile v1.1.9:SKILL.md\n\n---\nname: api-gateway\ndescription: Smart proxy for external API calls with retry, caching, rate limiting, and fallback providers. PERSISTS: API keys (chmod 0600 plaintext in keys.json), request/response cache metadata, and request logs. Network: outbound HTTPS only, with a strict provider-domain allowlist. Caches metadata by default; full response bodies are opt-in per provider.\n---\n\n# API Gateway ⚡\n\n> **Read this first.** This skill makes outbound HTTPS calls and writes plaintext API keys to disk. By installing or running it, you accept responsibility for the security of the keys you provide and the endpoints you target.\n\n**Stop duplicating API logic. Start routing through one smart gateway.**\n\n## What This Skill Does\n\nAPI Gateway is a local Node.js HTTP client wrapper that gives one call:\n\n- **Retry with exponential backoff** (3 attempts, 1s/2s/4s)\n- **Response caching** (default 5 min TTL, metadata-only)\n- **Rate-limit handling** (parses `x-ratelimit-remaining`, auto-fallback)\n- **Circuit breaker** (5-failure open, 30s cooldown, auto-recover)\n- **API key management** (masked display, chmod 0600 storage, env-var override)\n- **Fallback providers** (configurable per-provider chain)\n\n## ⚠️ Important Warnings\n\n### Outbound HTTPS Requests to Whitelisted Provider Domains\n`--call <provider> <endpoint>` sends HTTPS requests and, for configured providers, attaches a `Authorization: Bearer <key>` header. **The provider allowlist is strict: it is a domain-match check, not a `string.includes()` check.** A URL like `https://attacker.com/api?provider=openai` will NOT receive the key because the hostname must match the provider's registered allowlist entry. Review the allowlist in `--keys` output before adding sensitive keys.\n\n### API Keys Stored in Plaintext on Disk\nAPI keys saved via `--keys add` are written to `memory/api-gateway/keys.json` in plaintext, with file permissions set to `0600` (owner read/write only). The key is NEVER echoed back. Anyone with shell access to the workspace as the same user can still read it. For higher assurance, prefer environment variables: `OPENAI_API_KEY=sk-...` — API Gateway auto-detects any `PROVIDER_API_KEY` variable (e.g. `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`) and uses it without disk storage. It does NOT read arbitrary `env:NAME` references — only the `PROVIDER_API_KEY` pattern — so unrelated secrets are never pulled in.\n\n### Persistent Data Files (Disclosed Up Front)\nThe following files persist in `memory/api-gateway/` after any operation:\n- `keys.json` — API key storage, chmod 0600\n- `cache.json` — **Metadata-only by default** (status code, timestamp, response headers, response body *length*). The full response **body** is NOT stored unless you explicitly enable it per provider via `--cache-full <provider>`.\n- `request-log.json` — Provider name, status class (2xx/4xx/5xx), timestamp. Endpoint URLs, query strings, and request/response **bodies are NOT written here.** (Note: if *you* pass a URL or prompt inside a request body to `--call`, that body travels to the provider but is never persisted to the log or cache by this skill.)\n- `rate-limits.json` — Per-provider rate-limit state\n- `circuit-state.json` — Per-provider circuit-breaker state\n- `fallbacks.json` — Fallback provider mappings\n\nAll of these are intended, documented, and necessary for the skill's features. Default retention is unlimited unless cleared with `--cache --clear` and `--log --clear`.\n\n### Zero External Dependencies\nThis skill uses only Node.js built-ins (`http`, `https`, `fs`, `path`). There is no `package.json` to install, no transitive dependencies, no `npm install` step. The code you read is the code that runs.\n\n## Quick Start\n\n### Make an API call\n\n```bash\nnode skills/api-gateway/api-gateway.js --call openai https://api.openai.com/v1/chat/completions '{\"model\":\"gpt-4\",\"messages\":[{\"role\":\"user\",\"content\":\"hello\"}]}'\n```\n\nRetries up to 3 times with exponential backoff. Caches response **metadata** for 5 minutes.\n\n### Dry run (preview without executing)\n\n```bash\nnode skills/api-gateway/api-gateway.js --call --dry-run openai https://api.openai.com/v1/chat/completions\n```\n\n### Manage API keys\n\n```bash\n# List configured keys (masked, shows allowlist domains)\nnode skills/api-gateway/api-gateway.js --keys\n\n# Add a key (with provider allowlist)\nnode skills/api-gateway/api-gateway.js --keys add openai sk-abc123 --allow-domain api.openai.com\n\n# Remove a key\nnode skills/api-gateway/api-gateway.js --keys remove openai\n```\n\n### Use environment variables instead of stored keys (recommended for CI/ephemeral)\n\n```bash\nexport OPENAI_API_KEY=sk-abc123\nnode skills/api-gateway/api-gateway.js --call openai https://api.openai.com/v1/chat/completions '{\"model\":\"gpt-4\",\"messages\":[]}'\n```\n\nThe skill auto-detects `PROVIDER_API_KEY` env vars and uses them without disk storage. Stored keys take precedence if both are configured.\n\n### Cache, log, and rate status\n\n```bash\nnode skills/api-gateway/api-gateway.js --cache          # Show cache entries (metadata only)\nnode skills/api-gateway/api-gateway.js --cache --clear  # Clear cache\nnode skills/api-gateway/api-gateway.js --log            # Show request log (coarse: provider, status class, time)\nnode skills/api-gateway/api-gateway.js --log --clear    # Clear request log\nnode skills/api-gateway/api-gateway.js --rate openai    # Rate limit status\n```\n\n### Fallback providers and circuit breaker\n\n```bash\nnode skills/api-gateway/api-gateway.js --fallback openai anthropic\nnode skills/api-gateway/api-gateway.js --circuit --status\nnode skills/api-gateway/api-gateway.js --circuit openai --reset\n```\n\n### Status overview\n\n```bash\nnode skills/api-gateway/api-gateway.js --status\n```\n\n## Provider Allowlist (Security Boundary)\n\nThis is the most important section. The skill uses a **domain allowlist** to decide whether to inject the `Authorization: Bearer` header:\n\n- When you add a key with `--keys add <provider> <key> --allow-domain <domain>`, that domain is stored alongside the key.\n- On every call, the request URL's hostname is extracted and compared against the allowlist (exact match or `*.example.com` wildcard).\n- If the hostname does NOT match, the bearer token is omitted — the request still goes out, just without the key.\n- This means a malicious or mistyped endpoint URL cannot exfiltrate your key.\n\n**Example allowlist configurations:**\n\n```bash\n# Strict: only api.openai.com gets the OpenAI key\n--keys add openai sk-... --allow-domain api.openai.com\n\n# Wildcard: any *.anthropic.com endpoint\n--keys add anthropic sk-ant-... --allow-domain \"*.anthropic.com\"\n\n# Multi-domain (repeat flag)\n--keys add custom TOKEN --allow-domain api.example.com --allow-domain api-staging.example.com\n```\n\nIf you add a key WITHOUT `--allow-domain`, the key is still saved but the skill will **refuse to attach it to any request** until you add at least one allowlist entry. (You can edit `keys.json` to add `allowDomains: [\"api.openai.com\"]` directly.)\n\n## Features\n\n### Retry with Exponential Backoff\n- 3 retry attempts by default\n- Exponential backoff (1s, 2s, 4s)\n- All failures logged with attempt count\n\n### Response Caching (Metadata-Only by Default)\n- 5-minute TTL\n- Cache key = provider + endpoint + body hash\n- **Default behavior**: caches `{status, headers (redacted), timestamp, bodyLength}`. Body content is NOT stored.\n- **Opt-in full caching**: `--cache-full <provider>` enables full response body caching for that provider.\n- Auto-evicts expired entries\n- Cache hit detection prevents redundant calls\n\n### Rate Limit Handling\n- Tracks remaining requests from `x-ratelimit-remaining` headers\n- Auto-fallback when rate limited (if configured)\n- Status check via `--rate`\n\n### Key Management\n- Masked display (first 4 + last 4 chars)\n- Per-provider key storage in `memory/api-gateway/keys.json`\n- **chmod 0600** on the file (POSIX only; best-effort on Windows)\n- Environment-variable auto-detection (PROVIDER_API_KEY)\n- Allowlist attached to each key\n- Add/remove keys without exposing full values\n\n### Fallback Providers\n- Configurable per-provider fallback chain\n- Automatic failover on rate limit or error\n- No manual intervention needed\n\n### Circuit Breaker\n- Tracks failure rates per provider\n- Opens circuit after 5 consecutive failures\n- Auto-recovers after 30s cooldown (HALF-OPEN state)\n- Prevents cascading failures and saves API costs\n- CLI visibility: `--circuit --status` + `--circuit <name> --reset`\n\n## Configuration\n\nData files stored in: `memory/api-gateway/`\n\n- `keys.json` — API key storage (chmod 0600)\n- `fallbacks.json` — Fallback provider mappings\n- `cache.json` — Response cache (metadata-only by default)\n- `rate-limits.json` — Rate limit tracking\n- `request-log.json` — Request history (coarse: provider, status class, timestamp, NOT endpoints)\n- `circuit-state.json` — Circuit breaker state per provider\n\nOverride data directory:\n```bash\n--dir /path/to/data\n# or env var\nAPI_GATEWAY_DIR=/path/to/data node api-gateway.js --status\n```\n\n## Agent Protocol\n\nWhen making API calls:\n\n1. **Use the gateway** — `--call <provider> <endpoint> [body]` instead of direct fetch\n2. **Add keys with allowlist** — `--keys add <provider> <key> --allow-domain <domain>` before first use\n- **Prefer env vars in CI** — `PROVIDER_API_KEY` env vars bypass disk storage entirely. API Gateway auto-detects any `PROVIDER_API_KEY` environment variable (e.g. `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`) and uses it without disk storage. It does NOT read arbitrary environment variables — only the documented `PROVIDER_API_KEY` pattern — so unrelated secrets are never exposed to requests or local processing.\n4. **Set fallbacks** — `--fallback primary secondary` for critical providers\n5. **Check cache/log** — `--cache` / `--log` during heartbeats to monitor usage\n6. **Dry run** — `--call --dry-run` before executing important calls\n\n## Security Notes\n- Keys stored as plain text in JSON with chmod 0600 (POSIX)\n- For higher assurance, use environment variables (`PROVIDER_API_KEY`)\n- For production, integrate with a secrets manager\n- Masked output prevents accidental exposure in logs\n- Request log stores only provider + status class + timestamp (no endpoints)\n- Allowlist is a strict domain match, not a string contains\n- Code has zero external dependencies (no npm install)\n- ⚠️ **DATA LEAVES TO A THIRD PARTY:** every `--call` sends your request (URL, headers, body, prompts) to the provider endpoint YOU specify — a separate external service. Responses come back from that provider and may be retained by them per their own policy. This skill is NOT a transparent pass-through; it centralizes collection, storage, and forwarding of potentially sensitive data. Only call endpoints you trust.\n- ⚠️ **SENSITIVE DATA IN LOGS/CACHE (default vs opt-in):**\n  - The **request log** stores only provider name + status class + timestamp. It does NOT store endpoint URLs, query strings, or request/response bodies. (If you put a secret in a request body, that body goes to the provider but is never written to the request log.)\n  - **`cache.json` is metadata-only by default** (status, timestamp, response headers, body *length*). The full response **body** is written to disk ONLY when you explicitly enable `--cache-full <provider>`.\n  - So by default, endpoints/bodies you pass are NOT persisted locally by this skill. The only local exposure path is `--cache-full`, which stores complete responses. Clear caches after sensitive work (`--log --clear`, `--cache --clear`) and never use `--cache-full` for sensitive providers.\n- ⚠️ **FULL-BODY CACHING WRITES COMPLETE RESPONSES TO DISK:** `--cache-full <provider>` stores the ENTIRE response body (which may contain secrets, tokens, personal data, or proprietary content) in `cache.json`. This is a local data-exposure risk if the host/workspace is shared or later exfiltrated. Never use `--cache-full` with sensitive providers; prefer the default metadata-only cache.\n- ⚠️ **HTTPS ONLY:** API Gateway refuses to send any request over plain HTTP (it would expose bearer credentials on the wire). Set `API_GATEWAY_ALLOW_HTTP=1` only for non-credential plaintext endpoints.\n\n## What This Skill Does NOT Do\n\n- Does NOT install npm packages\n- Does NOT auto-update or phone home\n- Does NOT read environment variables silently — only the documented `PROVIDER_API_KEY` pattern\n- Does NOT send Authorization headers to URLs outside the allowlist\n- Does NOT cache full response bodies unless explicitly opted in per provider\n- Does NOT log full endpoint URLs or query strings\n\n## Design Principles\n\n1. **Zero setup** — Works immediately, no config needed\n2. **No dependencies** — Pure Node.js http/https, no npm packages\n3. **Resilient** — Retry, fallback, and rate limit handling built in\n4. **Transparent** — Masked keys, cache status, request logging\n5. **Composable** — Works with any HTTP API, not just specific providers\n6. **Fail-closed on security boundaries** — If the allowlist doesn't match, the key is not sent. If a file permission can't be set, the call still proceeds but a warning is logged.\n\nFile v1.1.9:README.md\n\n# API Gateway\n\nSmart proxy for external API calls with retry logic, caching, circuit breaker, and rate limiting.\n\n> ⚠️ **DATA LEAVES TO A THIRD PARTY:** every `--call` sends your request (URL, headers, body, prompts) to the provider endpoint *you* specify — a separate external service. Responses come back from that provider and may be retained by them per their own policy. This skill is NOT a transparent pass-through; it centralizes collection, storage, and forwarding of potentially sensitive data. Only call endpoints you trust. By default only request **metadata** (provider, status class, timestamp) and cache **metadata** are written to disk; the full response body is written only if you enable `--cache-full <provider>`.\n\n## Features\n\n- **HTTP Proxy** — Make API calls with automatic retry and timeout handling\n- **Circuit Breaker** — Automatic failure detection and cooldown (opens after 5 failures)\n- **Response Caching** — Cache API responses to reduce repeated calls\n- **Rate Limiting** — Per-provider rate limit tracking\n- **Fallback Providers** — Configure fallback providers for redundancy\n- **API Key Management** — Store, list, and remove API keys with masked output\n- **Request Logging** — Track request history for debugging\n\n## Installation\n\n```bash\n# The skill is auto-loaded by OpenClaw via the skill registry.\n# For standalone use:\nconst AG = require('./api-gateway.js');\n```\n\n## Commands\n\n```\n--call <provider> <endpoint> [body]       Make API call with retry/caching\n--call --dry-run <provider> <endpoint>    Preview call without executing\n--keys                                     List configured API keys (masked)\n--keys add <provider> <key>               Add API key\n--keys remove <provider>                  Remove API key\n--cache                                    Show cache status\n--cache --clear                            Clear cache\n--rate <provider>                          Check rate limit status\n--fallback <provider> <fallback>           Set fallback provider\n--status                                   Gateway status overview\n```\n\n## API\n\n### `makeRequest(url, method, headers, body, timeout)`\nMake an HTTP request with automatic retry and timeout.\n\n```javascript\nconst result = await AG.makeRequest('https://api.openai.com/v1/models', 'GET', {}, null, 30000);\n```\n\n### `maskKey(key)`\nMask a sensitive key for display (`sk-a****fgh`).\n\n### Circuit Breaker\n```javascript\nAG.getCircuitState('openai');     // Current state (CLOSED/OPEN/HALF-OPEN)\nAG.recordFailure('openai');       // Record a failure\nAG.recordSuccess('openai');       // Record a success (resets counter)\nAG.getCircuitStatus();            // All circuit states\nAG.resetCircuit('openai');        // Reset circuit breaker\n```\n\n### Key Management\n```javascript\nAG.addKey('openai', 'sk-...');    // Add API key\nAG.removeKey('openai');           // Remove API key\nAG.listKeys();                    // List all keys (masked)\n```\n\n### Cache\n```javascript\nAG.showCache();                   // Show cached responses\nAG.clearCache();                  // Clear all cached responses\n```\n\n### Fallback\n```javascript\nAG.setFallback('openai', 'anthropic');  // Set fallback provider\nAG.listFallbacks();                     // List all fallback providers\n```\n\n### Status\n```javascript\nAG.showStatus();                  // Full gateway status\n```\n\n## Security\n\n- API keys masked by default in console output\n- Circuit breaker prevents rapid retry cascades\n- Backoff strategy: 1s → 2s → 4s → 8s → 16s (exponential)\n- Max 5 retries per request\n- Cache expires after configurable TTL\n\n## Testing\n\n```bash\nnode tests/run-self-tests.js\n```\n\n### Test Coverage\n\n| Suite | Tests | Status |\n|---|---|---|\n| Self-tests (isolated) | 20 | ✅ Passing |\n\nFile v1.1.9:_meta.json\n\n{\n  \"ownerId\": \"kn7b6eyf5vc7khg5fr63pjm8xd82qvw5\",\n  \"slug\": \"api-proxy\",\n  \"version\": \"1.1.9\",\n  \"publishedAt\": 1785862095641\n}\n\nFile v1.1.9:skill-card.md\n\n## Description:\n\nSmart proxy for external API calls with retry, caching, rate limiting, and fallback providers.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[jlacroix82](https://clawhub.ai/user/jlacroix82)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and agents use this skill to route outbound HTTPS API requests through a local gateway with retry, metadata caching, rate-limit tracking, circuit breaking, fallback providers, and masked API-key handling.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Request bodies, prompts, headers, and responses are sent to the API provider endpoint selected by the user.\n\nMitigation: Use only trusted provider endpoints, configure strict allowlist domains, and avoid routing sensitive or regulated data unless the provider and use case are approved.\n\nRisk: API keys saved through the gateway are stored locally in plaintext, even though the file is created with owner-only permissions where supported.\n\nMitigation: Prefer PROVIDER_API_KEY environment variables or a secrets manager for valuable keys, and remove stored keys when they are no longer needed.\n\nRisk: Full response bodies can be written to the local cache when full-body caching is enabled.\n\nMitigation: Keep the default metadata-only cache for sensitive providers, avoid --cache-full for sensitive work, and clear cache and logs after sensitive sessions.\n\n## Reference(s):\n\n- [ClawHub skill page](https://clawhub.ai/jlacroix82/skills/api-proxy)\n\n## Skill Output:\n\n**Output Type(s):** [text, shell commands, configuration, guidance]\n\n**Output Format:** [Markdown with inline shell commands and command output summaries]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [May trigger outbound HTTPS requests to configured provider endpoints and may write local gateway state under memory/api-gateway/.]\n\n## Skill Version(s):\n\n1.1.9 (source: server release metadata and artifact/clawhub.yaml)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nFile v1.1.9:clawhub.yaml\n\nslug: api-proxy\nname: api-gateway\nowner: jlacroix82\ndescription: Smart proxy for external API calls with retry, caching, circuit breaker, and rate limiting. PERSISTS: API keys (chmod 0600 plaintext in keys.json), request/response cache metadata, and request logs. Network: outbound HTTPS only, with a strict provider-domain allowlist. Caches metadata by default; full response bodies are opt-in per provider. WARNING: Requests transmit prompts, request bodies, headers, and responses to third-party API providers. Keys apply allowlist to all sources (env-var or disk-stored).\nversion: 1.1.9\ntype: skill\nauthor: OpenClaw\nlicense: MIT\nkeywords:\n  - api\n  - proxy\n  - gateway\n  - circuit-breaker\n  - caching\n  - rate-limit\n  - allowlist\n  - security\ncapabilities:\n  - network\n  - filesystem\n  - environment\nentry: SKILL.md\ndependencies: []\npermissions:\n  - name: network.outbound\n    description: Outbound HTTPS to provider allowlist domains\n  - name: filesystem.read-write\n    description: Read/write data files in memory/api-gateway/ (keys.json chmod 0600)\n  - name: environment.read\n    description: Read PROVIDER_API_KEY environment variables\ndata_retention:\n  cache: 'metadata-only by default; full body opt-in per provider'\n  log: 'coarse: provider, status class, timestamp only — no endpoint paths or query strings stored'\n  keys: 'plaintext on disk with chmod 0600; env var override supported'\nsecurity_notes:\n  - 'WARNING: Requests transmit prompts, request bodies, headers, and responses to third-party API providers. Do not route sensitive/regulated data through the gateway.'\n  - 'Allowlist enforced for ALL keys (env-var and disk-stored) — both refuse auth if hostname not in allowlist'\n  - 'Keys stored as plain text in JSON with chmod 0600 (POSIX)'\n  - 'Request log stores only provider, status class, timestamp — no endpoint paths or query strings'\n  - 'For production, integrate with a secrets manager for API key storage'\n  - 'Use --call --dry-run before executing important calls'\n  - 'Clear logs/cache for sensitive work: --log --clear and --cache --clear'\n  - 'Masked output prevents accidental exposure in logs'\n\nArchive v1.1.8: 8 files, 21119 bytes\n\nFiles: api-gateway.js (32645b), clawhub.yaml (2136b), README.md (3137b), skill-card.md (2209b), SKILL.md (12716b), test/run-tests.js (3485b), tests/run-self-tests.js (6632b), _meta.json (128b)\n\nFile v1.1.8:SKILL.md\n\n---\nname: api-gateway\ndescription: Smart proxy for external API calls with retry, caching, rate limiting, and fallback providers. PERSISTS: API keys (chmod 0600 plaintext in keys.json), request/response cache metadata, and request logs. Network: outbound HTTPS only, with a strict provider-domain allowlist. Caches metadata by default; full response bodies are opt-in per provider.\n---\n\n# API Gateway ⚡\n\n> **Read this first.** This skill makes outbound HTTPS calls and writes plaintext API keys to disk. By installing or running it, you accept responsibility for the security of the keys you provide and the endpoints you target.\n\n**Stop duplicating API logic. Start routing through one smart gateway.**\n\n## What This Skill Does\n\nAPI Gateway is a local Node.js HTTP client wrapper that gives one call:\n\n- **Retry with exponential backoff** (3 attempts, 1s/2s/4s)\n- **Response caching** (default 5 min TTL, metadata-only)\n- **Rate-limit handling** (parses `x-ratelimit-remaining`, auto-fallback)\n- **Circuit breaker** (5-failure open, 30s cooldown, auto-recover)\n- **API key management** (masked display, chmod 0600 storage, env-var override)\n- **Fallback providers** (configurable per-provider chain)\n\n## ⚠️ Important Warnings\n\n### Outbound HTTPS Requests to Whitelisted Provider Domains\n`--call <provider> <endpoint>` sends HTTPS requests and, for configured providers, attaches a `Authorization: Bearer <key>` header. **The provider allowlist is strict: it is a domain-match check, not a `string.includes()` check.** A URL like `https://attacker.com/api?provider=openai` will NOT receive the key because the hostname must match the provider's registered allowlist entry. Review the allowlist in `--keys` output before adding sensitive keys.\n\n### API Keys Stored in Plaintext on Disk\nAPI keys saved via `--keys add` are written to `memory/api-gateway/keys.json` in plaintext, with file permissions set to `0600` (owner read/write only). The key is NEVER echoed back. Anyone with shell access to the workspace as the same user can still read it. For higher assurance, prefer environment variables: `OPENAI_API_KEY=sk-...` — API Gateway auto-detects any `PROVIDER_API_KEY` variable (e.g. `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`) and uses it without disk storage. It does NOT read arbitrary `env:NAME` references — only the `PROVIDER_API_KEY` pattern — so unrelated secrets are never pulled in.\n\n### Persistent Data Files (Disclosed Up Front)\nThe following files persist in `memory/api-gateway/` after any operation:\n- `keys.json` — API key storage, chmod 0600\n- `cache.json` — **Metadata-only by default** (status code, timestamp, response headers, response body *length*). The full response **body** is NOT stored unless you explicitly enable it per provider via `--cache-full <provider>`.\n- `request-log.json` — Provider name, status class (2xx/4xx/5xx), timestamp. Endpoint URLs, query strings, and request/response **bodies are NOT written here.** (Note: if *you* pass a URL or prompt inside a request body to `--call`, that body travels to the provider but is never persisted to the log or cache by this skill.)\n- `rate-limits.json` — Per-provider rate-limit state\n- `circuit-state.json` — Per-provider circuit-breaker state\n- `fallbacks.json` — Fallback provider mappings\n\nAll of these are intended, documented, and necessary for the skill's features. Default retention is unlimited unless cleared with `--cache --clear` and `--log --clear`.\n\n### Zero External Dependencies\nThis skill uses only Node.js built-ins (`http`, `https`, `fs`, `path`). There is no `package.json` to install, no transitive dependencies, no `npm install` step. The code you read is the code that runs.\n\n## Quick Start\n\n### Make an API call\n\n```bash\nnode skills/api-gateway/api-gateway.js --call openai https://api.openai.com/v1/chat/completions '{\"model\":\"gpt-4\",\"messages\":[{\"role\":\"user\",\"content\":\"hello\"}]}'\n```\n\nRetries up to 3 times with exponential backoff. Caches response **metadata** for 5 minutes.\n\n### Dry run (preview without executing)\n\n```bash\nnode skills/api-gateway/api-gateway.js --call --dry-run openai https://api.openai.com/v1/chat/completions\n```\n\n### Manage API keys\n\n```bash\n# List configured keys (masked, shows allowlist domains)\nnode skills/api-gateway/api-gateway.js --keys\n\n# Add a key (with provider allowlist)\nnode skills/api-gateway/api-gateway.js --keys add openai sk-abc123 --allow-domain api.openai.com\n\n# Remove a key\nnode skills/api-gateway/api-gateway.js --keys remove openai\n```\n\n### Use environment variables instead of stored keys (recommended for CI/ephemeral)\n\n```bash\nexport OPENAI_API_KEY=sk-abc123\nnode skills/api-gateway/api-gateway.js --call openai https://api.openai.com/v1/chat/completions '{\"model\":\"gpt-4\",\"messages\":[]}'\n```\n\nThe skill auto-detects `PROVIDER_API_KEY` env vars and uses them without disk storage. Stored keys take precedence if both are configured.\n\n### Cache, log, and rate status\n\n```bash\nnode skills/api-gateway/api-gateway.js --cache          # Show cache entries (metadata only)\nnode skills/api-gateway/api-gateway.js --cache --clear  # Clear cache\nnode skills/api-gateway/api-gateway.js --log            # Show request log (coarse: provider, status class, time)\nnode skills/api-gateway/api-gateway.js --log --clear    # Clear request log\nnode skills/api-gateway/api-gateway.js --rate openai    # Rate limit status\n```\n\n### Fallback providers and circuit breaker\n\n```bash\nnode skills/api-gateway/api-gateway.js --fallback openai anthropic\nnode skills/api-gateway/api-gateway.js --circuit --status\nnode skills/api-gateway/api-gateway.js --circuit openai --reset\n```\n\n### Status overview\n\n```bash\nnode skills/api-gateway/api-gateway.js --status\n```\n\n## Provider Allowlist (Security Boundary)\n\nThis is the most important section. The skill uses a **domain allowlist** to decide whether to inject the `Authorization: Bearer` header:\n\n- When you add a key with `--keys add <provider> <key> --allow-domain <domain>`, that domain is stored alongside the key.\n- On every call, the request URL's hostname is extracted and compared against the allowlist (exact match or `*.example.com` wildcard).\n- If the hostname does NOT match, the bearer token is omitted — the request still goes out, just without the key.\n- This means a malicious or mistyped endpoint URL cannot exfiltrate your key.\n\n**Example allowlist configurations:**\n\n```bash\n# Strict: only api.openai.com gets the OpenAI key\n--keys add openai sk-... --allow-domain api.openai.com\n\n# Wildcard: any *.anthropic.com endpoint\n--keys add anthropic sk-ant-... --allow-domain \"*.anthropic.com\"\n\n# Multi-domain (repeat flag)\n--keys add custom TOKEN --allow-domain api.example.com --allow-domain api-staging.example.com\n```\n\nIf you add a key WITHOUT `--allow-domain`, the key is still saved but the skill will **refuse to attach it to any request** until you add at least one allowlist entry. (You can edit `keys.json` to add `allowDomains: [\"api.openai.com\"]` directly.)\n\n## Features\n\n### Retry with Exponential Backoff\n- 3 retry attempts by default\n- Exponential backoff (1s, 2s, 4s)\n- All failures logged with attempt count\n\n### Response Caching (Metadata-Only by Default)\n- 5-minute TTL\n- Cache key = provider + endpoint + body hash\n- **Default behavior**: caches `{status, headers (redacted), timestamp, bodyLength}`. Body content is NOT stored.\n- **Opt-in full caching**: `--cache-full <provider>` enables full response body caching for that provider.\n- Auto-evicts expired entries\n- Cache hit detection prevents redundant calls\n\n### Rate Limit Handling\n- Tracks remaining requests from `x-ratelimit-remaining` headers\n- Auto-fallback when rate limited (if configured)\n- Status check via `--rate`\n\n### Key Management\n- Masked display (first 4 + last 4 chars)\n- Per-provider key storage in `memory/api-gateway/keys.json`\n- **chmod 0600** on the file (POSIX only; best-effort on Windows)\n- Environment-variable auto-detection (PROVIDER_API_KEY)\n- Allowlist attached to each key\n- Add/remove keys without exposing full values\n\n### Fallback Providers\n- Configurable per-provider fallback chain\n- Automatic failover on rate limit or error\n- No manual intervention needed\n\n### Circuit Breaker\n- Tracks failure rates per provider\n- Opens circuit after 5 consecutive failures\n- Auto-recovers after 30s cooldown (HALF-OPEN state)\n- Prevents cascading failures and saves API costs\n- CLI visibility: `--circuit --status` + `--circuit <name> --reset`\n\n## Configuration\n\nData files stored in: `memory/api-gateway/`\n\n- `keys.json` — API key storage (chmod 0600)\n- `fallbacks.json` — Fallback provider mappings\n- `cache.json` — Response cache (metadata-only by default)\n- `rate-limits.json` — Rate limit tracking\n- `request-log.json` — Request history (coarse: provider, status class, timestamp, NOT endpoints)\n- `circuit-state.json` — Circuit breaker state per provider\n\nOverride data directory:\n```bash\n--dir /path/to/data\n# or env var\nAPI_GATEWAY_DIR=/path/to/data node api-gateway.js --status\n```\n\n## Agent Protocol\n\nWhen making API calls:\n\n1. **Use the gateway** — `--call <provider> <endpoint> [body]` instead of direct fetch\n2. **Add keys with allowlist** — `--keys add <provider> <key> --allow-domain <domain>` before first use\n- **Prefer env vars in CI** — `PROVIDER_API_KEY` env vars bypass disk storage entirely. API Gateway auto-detects any `PROVIDER_API_KEY` environment variable (e.g. `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`) and uses it without disk storage. It does NOT read arbitrary environment variables — only the documented `PROVIDER_API_KEY` pattern — so unrelated secrets are never exposed to requests or local processing.\n4. **Set fallbacks** — `--fallback primary secondary` for critical providers\n5. **Check cache/log** — `--cache` / `--log` during heartbeats to monitor usage\n6. **Dry run** — `--call --dry-run` before executing important calls\n\n## Security Notes\n- Keys stored as plain text in JSON with chmod 0600 (POSIX)\n- For higher assurance, use environment variables (`PROVIDER_API_KEY`)\n- For production, integrate with a secrets manager\n- Masked output prevents accidental exposure in logs\n- Request log stores only provider + status class + timestamp (no endpoints)\n- Allowlist is a strict domain match, not a string contains\n- Code has zero external dependencies (no npm install)\n- ⚠️ **DATA LEAVES TO A THIRD PARTY:** every `--call` sends your request (URL, headers, body, prompts) to the provider endpoint YOU specify — a separate external service. Responses come back from that provider and may be retained by them per their own policy. This skill is NOT a transparent pass-through; it centralizes collection, storage, and forwarding of potentially sensitive data. Only call endpoints you trust.\n- ⚠️ **SENSITIVE DATA IN LOGS/CACHE:** request bodies, response headers, and endpoints you pass may themselves contain API keys, tokens, or prompts. The request log, `cache.json` (especially with `--cache-full`), and `request-log.json` persist this data to disk. Clear them after sensitive work (`--log --clear`, `--cache --clear`) and never call `--cache-full` for sensitive providers.\n- ⚠️ **FULL-BODY CACHING WRITES COMPLETE RESPONSES TO DISK:** `--cache-full <provider>` stores the ENTIRE response body (which may contain secrets, tokens, personal data, or proprietary content) in `cache.json`. This is a local data-exposure risk if the host/workspace is shared or later exfiltrated. Never use `--cache-full` with sensitive providers; prefer the default metadata-only cache.\n- ⚠️ **HTTPS ONLY:** API Gateway refuses to send any request over plain HTTP (it would expose bearer credentials on the wire). Set `API_GATEWAY_ALLOW_HTTP=1` only for non-credential plaintext endpoints.\n\n## What This Skill Does NOT Do\n\n- Does NOT install npm packages\n- Does NOT auto-update or phone home\n- Does NOT read environment variables silently — only the documented `PROVIDER_API_KEY` pattern\n- Does NOT send Authorization headers to URLs outside the allowlist\n- Does NOT cache full response bodies unless explicitly opted in per provider\n- Does NOT log full endpoint URLs or query strings\n\n## Design Principles\n\n1. **Zero setup** — Works immediately, no config needed\n2. **No dependencies** — Pure Node.js http/https, no npm packages\n3. **Resilient** — Retry, fallback, and rate limit handling built in\n4. **Transparent** — Masked keys, cache status, request logging\n5. **Composable** — Works with any HTTP API, not just specific providers\n6. **Fail-closed on security boundaries** — If the allowlist doesn't match, the key is not sent. If a file permission can't be set, the call still proceeds but a warning is logged.\n\nFile v1.1.8:README.md\n\n# API Gateway\n\nSmart proxy for external API calls with retry logic, caching, circuit breaker, and rate limiting.\n\n## Features\n\n- **HTTP Proxy** — Make API calls with automatic retry and timeout handling\n- **Circuit Breaker** — Automatic failure detection and cooldown (opens after 5 failures)\n- **Response Caching** — Cache API responses to reduce repeated calls\n- **Rate Limiting** — Per-provider rate limit tracking\n- **Fallback Providers** — Configure fallback providers for redundancy\n- **API Key Management** — Store, list, and remove API keys with masked output\n- **Request Logging** — Track request history for debugging\n\n## Installation\n\n```bash\n# The skill is auto-loaded by OpenClaw via the skill registry.\n# For standalone use:\nconst AG = require('./api-gateway.js');\n```\n\n## Commands\n\n```\n--call <provider> <endpoint> [body]       Make API call with retry/caching\n--call --dry-run <provider> <endpoint>    Preview call without executing\n--keys                                     List configured API keys (masked)\n--keys add <provider> <key>               Add API key\n--keys remove <provider>                  Remove API key\n--cache                                    Show cache status\n--cache --clear                            Clear cache\n--rate <provider>                          Check rate limit status\n--fallback <provider> <fallback>           Set fallback provider\n--status                                   Gateway status overview\n```\n\n## API\n\n### `makeRequest(url, method, headers, body, timeout)`\nMake an HTTP request with automatic retry and timeout.\n\n```javascript\nconst result = await AG.makeRequest('https://api.openai.com/v1/models', 'GET', {}, null, 30000);\n```\n\n### `maskKey(key)`\nMask a sensitive key for display (`sk-a****fgh`).\n\n### Circuit Breaker\n```javascript\nAG.getCircuitState('openai');     // Current state (CLOSED/OPEN/HALF-OPEN)\nAG.recordFailure('openai');       // Record a failure\nAG.recordSuccess('openai');       // Record a success (resets counter)\nAG.getCircuitStatus();            // All circuit states\nAG.resetCircuit('openai');        // Reset circuit breaker\n```\n\n### Key Management\n```javascript\nAG.addKey('openai', 'sk-...');    // Add API key\nAG.removeKey('openai');           // Remove API key\nAG.listKeys();                    // List all keys (masked)\n```\n\n### Cache\n```javascript\nAG.showCache();                   // Show cached responses\nAG.clearCache();                  // Clear all cached responses\n```\n\n### Fallback\n```javascript\nAG.setFallback('openai', 'anthropic');  // Set fallback provider\nAG.listFallbacks();                     // List all fallback providers\n```\n\n### Status\n```javascript\nAG.showStatus();                  // Full gateway status\n```\n\n## Security\n\n- API keys masked by default in console output\n- Circuit breaker prevents rapid retry cascades\n- Backoff strategy: 1s → 2s → 4s → 8s → 16s (exponential)\n- Max 5 retries per request\n- Cache expires after configurable TTL\n\n## Testing\n\n```bash\nnode tests/run-self-tests.js\n```\n\n### Test Coverage\n\n| Suite | Tests | Status |\n|---|---|---|\n| Self-tests (isolated) | 20 | ✅ Passing |\n\nFile v1.1.8:_meta.json\n\n{\n  \"ownerId\": \"kn7b6eyf5vc7khg5fr63pjm8xd82qvw5\",\n  \"slug\": \"api-proxy\",\n  \"version\": \"1.1.8\",\n  \"publishedAt\": 1785857315005\n}\n\nFile v1.1.8:skill-card.md\n\n## Description:\n\nSmart proxy for external API calls with retry, caching, rate limiting, and fallback providers.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[jlacroix82](https://clawhub.ai/user/jlacroix82)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and agent operators use this skill to route outbound API requests through a local gateway with retries, caching, rate-limit tracking, fallback providers, and API key handling.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Sensitive request bodies may be persisted in cache keys despite metadata-only cache claims.\n\nMitigation: Avoid sending secrets or regulated data in request bodies, clear cache after sensitive work, and treat memory/api-gateway as sensitive local storage.\n\nRisk: Plaintext API keys can be stored on disk in keys.json.\n\nMitigation: Prefer scoped PROVIDER_API_KEY environment variables or a secrets manager, and only use disk-stored keys in workspaces with appropriate local access controls.\n\nRisk: Requests transmit URLs, headers, bodies, and prompts to external provider endpoints selected by the user.\n\nMitigation: Use only trusted provider endpoints, review allowlists before adding keys, and use dry-run mode before important calls.\n\n## Reference(s):\n\n- [ClawHub skill page](https://clawhub.ai/jlacroix82/skills/api-proxy)\n- [README](artifact/README.md)\n- [Skill source](artifact/SKILL.md)\n- [ClawHub manifest](artifact/clawhub.yaml)\n\n## Skill Output:\n\n**Output Type(s):** [text, markdown, code, shell commands, configuration, guidance]\n\n**Output Format:** [Markdown guidance with shell commands and JavaScript configuration examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [May execute outbound HTTPS requests and write local gateway state when invoked by an agent.]\n\n## Skill Version(s):\n\n1.1.8 (source: server release evidence and artifact/clawhub.yaml)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nFile v1.1.8:clawhub.yaml\n\nslug: api-proxy\nname: api-gateway\nowner: jlacroix82\ndescription: Smart proxy for external API calls with retry, caching, circuit breaker, and rate limiting. PERSISTS: API keys (chmod 0600 plaintext in keys.json), request/response cache metadata, and request logs. Network: outbound HTTPS only, with a strict provider-domain allowlist. Caches metadata by default; full response bodies are opt-in per provider. WARNING: Requests transmit prompts, request bodies, headers, and responses to third-party API providers. Keys apply allowlist to all sources (env-var or disk-stored).\nversion: 1.1.8\ntype: skill\nauthor: OpenClaw\nlicense: MIT\nkeywords:\n  - api\n  - proxy\n  - gateway\n  - circuit-breaker\n  - caching\n  - rate-limit\n  - allowlist\n  - security\ncapabilities:\n  - network\n  - filesystem\n  - environment\nentry: SKILL.md\ndependencies: []\npermissions:\n  - name: network.outbound\n    description: Outbound HTTPS to provider allowlist domains\n  - name: filesystem.read-write\n    description: Read/write data files in memory/api-gateway/ (keys.json chmod 0600)\n  - name: environment.read\n    description: Read PROVIDER_API_KEY environment variables\ndata_retention:\n  cache: 'metadata-only by default; full body opt-in per provider'\n  log: 'coarse: provider, status class, timestamp only — no endpoint paths or query strings stored'\n  keys: 'plaintext on disk with chmod 0600; env var override supported'\nsecurity_notes:\n  - 'WARNING: Requests transmit prompts, request bodies, headers, and responses to third-party API providers. Do not route sensitive/regulated data through the gateway.'\n  - 'Allowlist enforced for ALL keys (env-var and disk-stored) — both refuse auth if hostname not in allowlist'\n  - 'Keys stored as plain text in JSON with chmod 0600 (POSIX)'\n  - 'Request log stores only provider, status class, timestamp — no endpoint paths or query strings'\n  - 'For production, integrate with a secrets manager for API key storage'\n  - 'Use --call --dry-run before executing important calls'\n  - 'Clear logs/cache for sensitive work: --log --clear and --cache --clear'\n  - 'Masked output prevents accidental exposure in logs'\n\nArchive v1.1.7: 8 files, 20849 bytes\n\nFiles: api-gateway.js (32197b), clawhub.yaml (2136b), README.md (3137b), skill-card.md (2288b), SKILL.md (12455b), test/run-tests.js (3485b), tests/run-self-tests.js (6632b), _meta.json (128b)\n\nFile v1.1.7:SKILL.md\n\n---\nname: api-gateway\ndescription: Smart proxy for external API calls with retry, caching, rate limiting, and fallback providers. PERSISTS: API keys (chmod 0600 plaintext in keys.json), request/response cache metadata, and request logs. Network: outbound HTTPS only, with a strict provider-domain allowlist. Caches metadata by default; full response bodies are opt-in per provider.\n---\n\n# API Gateway ⚡\n\n> **Read this first.** This skill makes outbound HTTPS calls and writes plaintext API keys to disk. By installing or running it, you accept responsibility for the security of the keys you provide and the endpoints you target.\n\n**Stop duplicating API logic. Start routing through one smart gateway.**\n\n## What This Skill Does\n\nAPI Gateway is a local Node.js HTTP client wrapper that gives one call:\n\n- **Retry with exponential backoff** (3 attempts, 1s/2s/4s)\n- **Response caching** (default 5 min TTL, metadata-only)\n- **Rate-limit handling** (parses `x-ratelimit-remaining`, auto-fallback)\n- **Circuit breaker** (5-failure open, 30s cooldown, auto-recover)\n- **API key management** (masked display, chmod 0600 storage, env-var override)\n- **Fallback providers** (configurable per-provider chain)\n\n## ⚠️ Important Warnings\n\n### Outbound HTTPS Requests to Whitelisted Provider Domains\n`--call <provider> <endpoint>` sends HTTPS requests and, for configured providers, attaches a `Authorization: Bearer <key>` header. **The provider allowlist is strict: it is a domain-match check, not a `string.includes()` check.** A URL like `https://attacker.com/api?provider=openai` will NOT receive the key because the hostname must match the provider's registered allowlist entry. Review the allowlist in `--keys` output before adding sensitive keys.\n\n### API Keys Stored in Plaintext on Disk\nAPI keys saved via `--keys add` are written to `memory/api-gateway/keys.json` in plaintext, with file permissions set to `0600` (owner read/write only). The key is NEVER echoed back. Anyone with shell access to the workspace as the same user can still read it. For higher assurance, prefer environment variables: `OPENAI_API_KEY=sk-...` — API Gateway auto-detects any `PROVIDER_API_KEY` variable (e.g. `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`) and uses it without disk storage. It does NOT read arbitrary `env:NAME` references — only the `PROVIDER_API_KEY` pattern — so unrelated secrets are never pulled in.\n\n### Persistent Data Files (Disclosed Up Front)\nThe following files persist in `memory/api-gateway/` after any operation:\n- `keys.json` — API key storage, chmod 0600\n- `cache.json` — **Metadata-only by default** (status code, timestamp, headers, body length). Full response body caching is opt-in per provider via `--cache-full <provider>`.\n- `request-log.json` — Provider name, status class (2xx/4xx/5xx), timestamp. Endpoints and query strings are NOT stored.\n- `rate-limits.json` — Per-provider rate-limit state\n- `circuit-state.json` — Per-provider circuit-breaker state\n- `fallbacks.json` — Fallback provider mappings\n\nAll of these are intended, documented, and necessary for the skill's features. Default retention is unlimited unless cleared with `--cache --clear` and `--log --clear`.\n\n### Zero External Dependencies\nThis skill uses only Node.js built-ins (`http`, `https`, `fs`, `path`). There is no `package.json` to install, no transitive dependencies, no `npm install` step. The code you read is the code that runs.\n\n## Quick Start\n\n### Make an API call\n\n```bash\nnode skills/api-gateway/api-gateway.js --call openai https://api.openai.com/v1/chat/completions '{\"model\":\"gpt-4\",\"messages\":[{\"role\":\"user\",\"content\":\"hello\"}]}'\n```\n\nRetries up to 3 times with exponential backoff. Caches response **metadata** for 5 minutes.\n\n### Dry run (preview without executing)\n\n```bash\nnode skills/api-gateway/api-gateway.js --call --dry-run openai https://api.openai.com/v1/chat/completions\n```\n\n### Manage API keys\n\n```bash\n# List configured keys (masked, shows allowlist domains)\nnode skills/api-gateway/api-gateway.js --keys\n\n# Add a key (with provider allowlist)\nnode skills/api-gateway/api-gateway.js --keys add openai sk-abc123 --allow-domain api.openai.com\n\n# Remove a key\nnode skills/api-gateway/api-gateway.js --keys remove openai\n```\n\n### Use environment variables instead of stored keys (recommended for CI/ephemeral)\n\n```bash\nexport OPENAI_API_KEY=sk-abc123\nnode skills/api-gateway/api-gateway.js --call openai https://api.openai.com/v1/chat/completions '{\"model\":\"gpt-4\",\"messages\":[]}'\n```\n\nThe skill auto-detects `PROVIDER_API_KEY` env vars and uses them without disk storage. Stored keys take precedence if both are configured.\n\n### Cache, log, and rate status\n\n```bash\nnode skills/api-gateway/api-gateway.js --cache          # Show cache entries (metadata only)\nnode skills/api-gateway/api-gateway.js --cache --clear  # Clear cache\nnode skills/api-gateway/api-gateway.js --log            # Show request log (coarse: provider, status class, time)\nnode skills/api-gateway/api-gateway.js --log --clear    # Clear request log\nnode skills/api-gateway/api-gateway.js --rate openai    # Rate limit status\n```\n\n### Fallback providers and circuit breaker\n\n```bash\nnode skills/api-gateway/api-gateway.js --fallback openai anthropic\nnode skills/api-gateway/api-gateway.js --circuit --status\nnode skills/api-gateway/api-gateway.js --circuit openai --reset\n```\n\n### Status overview\n\n```bash\nnode skills/api-gateway/api-gateway.js --status\n```\n\n## Provider Allowlist (Security Boundary)\n\nThis is the most important section. The skill uses a **domain allowlist** to decide whether to inject the `Authorization: Bearer` header:\n\n- When you add a key with `--keys add <provider> <key> --allow-domain <domain>`, that domain is stored alongside the key.\n- On every call, the request URL's hostname is extracted and compared against the allowlist (exact match or `*.example.com` wildcard).\n- If the hostname does NOT match, the bearer token is omitted — the request still goes out, just without the key.\n- This means a malicious or mistyped endpoint URL cannot exfiltrate your key.\n\n**Example allowlist configurations:**\n\n```bash\n# Strict: only api.openai.com gets the OpenAI key\n--keys add openai sk-... --allow-domain api.openai.com\n\n# Wildcard: any *.anthropic.com endpoint\n--keys add anthropic sk-ant-... --allow-domain \"*.anthropic.com\"\n\n# Multi-domain (repeat flag)\n--keys add custom TOKEN --allow-domain api.example.com --allow-domain api-staging.example.com\n```\n\nIf you add a key WITHOUT `--allow-domain`, the key is still saved but the skill will **refuse to attach it to any request** until you add at least one allowlist entry. (You can edit `keys.json` to add `allowDomains: [\"api.openai.com\"]` directly.)\n\n## Features\n\n### Retry with Exponential Backoff\n- 3 retry attempts by default\n- Exponential backoff (1s, 2s, 4s)\n- All failures logged with attempt count\n\n### Response Caching (Metadata-Only by Default)\n- 5-minute TTL\n- Cache key = provider + endpoint + body hash\n- **Default behavior**: caches `{status, headers (redacted), timestamp, bodyLength}`. Body content is NOT stored.\n- **Opt-in full caching**: `--cache-full <provider>` enables full response body caching for that provider.\n- Auto-evicts expired entries\n- Cache hit detection prevents redundant calls\n\n### Rate Limit Handling\n- Tracks remaining requests from `x-ratelimit-remaining` headers\n- Auto-fallback when rate limited (if configured)\n- Status check via `--rate`\n\n### Key Management\n- Masked display (first 4 + last 4 chars)\n- Per-provider key storage in `memory/api-gateway/keys.json`\n- **chmod 0600** on the file (POSIX only; best-effort on Windows)\n- Environment-variable auto-detection (PROVIDER_API_KEY)\n- Allowlist attached to each key\n- Add/remove keys without exposing full values\n\n### Fallback Providers\n- Configurable per-provider fallback chain\n- Automatic failover on rate limit or error\n- No manual intervention needed\n\n### Circuit Breaker\n- Tracks failure rates per provider\n- Opens circuit after 5 consecutive failures\n- Auto-recovers after 30s cooldown (HALF-OPEN state)\n- Prevents cascading failures and saves API costs\n- CLI visibility: `--circuit --status` + `--circuit <name> --reset`\n\n## Configuration\n\nData files stored in: `memory/api-gateway/`\n\n- `keys.json` — API key storage (chmod 0600)\n- `fallbacks.json` — Fallback provider mappings\n- `cache.json` — Response cache (metadata-only by default)\n- `rate-limits.json` — Rate limit tracking\n- `request-log.json` — Request history (coarse: provider, status class, timestamp, NOT endpoints)\n- `circuit-state.json` — Circuit breaker state per provider\n\nOverride data directory:\n```bash\n--dir /path/to/data\n# or env var\nAPI_GATEWAY_DIR=/path/to/data node api-gateway.js --status\n```\n\n## Agent Protocol\n\nWhen making API calls:\n\n1. **Use the gateway** — `--call <provider> <endpoint> [body]` instead of direct fetch\n2. **Add keys with allowlist** — `--keys add <provider> <key> --allow-domain <domain>` before first use\n- **Prefer env vars in CI** — `PROVIDER_API_KEY` env vars bypass disk storage entirely. API Gateway auto-detects any `PROVIDER_API_KEY` environment variable (e.g. `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`) and uses it without disk storage. It does NOT read arbitrary environment variables — only the documented `PROVIDER_API_KEY` pattern — so unrelated secrets are never exposed to requests or local processing.\n4. **Set fallbacks** — `--fallback primary secondary` for critical providers\n5. **Check cache/log** — `--cache` / `--log` during heartbeats to monitor usage\n6. **Dry run** — `--call --dry-run` before executing important calls\n\n## Security Notes\n- Keys stored as plain text in JSON with chmod 0600 (POSIX)\n- For higher assurance, use environment variables (`PROVIDER_API_KEY`)\n- For production, integrate with a secrets manager\n- Masked output prevents accidental exposure in logs\n- Request log stores only provider + status class + timestamp (no endpoints)\n- Allowlist is a strict domain match, not a string contains\n- Code has zero external dependencies (no npm install)\n- ⚠️ **DATA LEAVES TO A THIRD PARTY:** every `--call` sends your request (URL, headers, body, prompts) to the provider endpoint YOU specify — a separate external service. Responses come back from that provider and may be retained by them per their own policy. This skill is NOT a transparent pass-through; it centralizes collection, storage, and forwarding of potentially sensitive data. Only call endpoints you trust.\n- ⚠️ **SENSITIVE DATA IN LOGS/CACHE:** request bodies, response headers, and endpoints you pass may themselves contain API keys, tokens, or prompts. The request log, `cache.json` (especially with `--cache-full`), and `request-log.json` persist this data to disk. Clear them after sensitive work (`--log --clear`, `--cache --clear`) and never call `--cache-full` for sensitive providers.\n- ⚠️ **FULL-BODY CACHING WRITES COMPLETE RESPONSES TO DISK:** `--cache-full <provider>` stores the ENTIRE response body (which may contain secrets, tokens, personal data, or proprietary content) in `cache.json`. This is a local data-exposure risk if the host/workspace is shared or later exfiltrated. Never use `--cache-full` with sensitive providers; prefer the default metadata-only cache.\n- ⚠️ **HTTPS ONLY:** API Gateway refuses to send any request over plain HTTP (it would expose bearer credentials on the wire). Set `API_GATEWAY_ALLOW_HTTP=1` only for non-credential plaintext endpoints.\n\n## What This Skill Does NOT Do\n\n- Does NOT install npm packages\n- Does NOT auto-update or phone home\n- Does NOT read environment variables silently — only the documented `PROVIDER_API_KEY` pattern\n- Does NOT send Authorization headers to URLs outside the allowlist\n- Does NOT cache full response bodies unless explicitly opted in per provider\n- Does NOT log full endpoint URLs or query strings\n\n## Design Principles\n\n1. **Zero setup** — Works immediately, no config needed\n2. **No dependencies** — Pure Node.js http/https, no npm packages\n3. **Resilient** — Retry, fallback, and rate limit handling built in\n4. **Transparent** — Masked keys, cache status, request logging\n5. **Composable** — Works with any HTTP API, not just specific providers\n6. **Fail-closed on security boundaries** — If the allowlist doesn't match, the key is not sent. If a file permission can't be set, the call still proceeds but a warning is logged.\n\nFile v1.1.7:README.md\n\n# API Gateway\n\nSmart proxy for external API calls with retry logic, caching, circuit breaker, and rate limiting.\n\n## Features\n\n- **HTTP Proxy** — Make API calls with automatic retry and timeout handling\n- **Circuit Breaker** — Automatic failure detection and cooldown (opens after 5 failures)\n- **Response Caching** — Cache API responses to reduce repeated calls\n- **Rate Limiting** — Per-provider rate limit tracking\n- **Fallback Providers** — Configure fallback providers for redundancy\n- **API Key Management** — Store, list, and remove API keys with masked output\n- **Request Logging** — Track request history for debugging\n\n## Installation\n\n```bash\n# The skill is auto-loaded by OpenClaw via the skill registry.\n# For standalone use:\nconst AG = require('./api-gateway.js');\n```\n\n## Commands\n\n```\n--call <provider> <endpoint> [body]       Make API call with retry/caching\n--call --dry-run <provider> <endpoint>    Preview call without executing\n--keys                                     List configured API keys (masked)\n--keys add <provider> <key>               Add API key\n--keys remove <provider>                  Remove API key\n--cache                                    Show cache status\n--cache --clear                            Clear cache\n--rate <provider>                          Check rate limit status\n--fallback <provider> <fallback>           Set fallback provider\n--status                                   Gateway status overview\n```\n\n## API\n\n### `makeRequest(url, method, headers, body, timeout)`\nMake an HTTP request with automatic retry and timeout.\n\n```javascript\nconst result = await AG.makeRequest('https://api.openai.com/v1/models', 'GET', {}, null, 30000);\n```\n\n### `maskKey(key)`\nMask a sensitive key for display (`sk-a****fgh`).\n\n### Circuit Breaker\n```javascript\nAG.getCircuitState('openai');     // Current state (CLOSED/OPEN/HALF-OPEN)\nAG.recordFailure('openai');       // Record a failure\nAG.recordSuccess('openai');       // Record a success (resets counter)\nAG.getCircuitStatus();            // All circuit states\nAG.resetCircuit('openai');        // Reset circuit breaker\n```\n\n### Key Management\n```javascript\nAG.addKey('openai', 'sk-...');    // Add API key\nAG.removeKey('openai');           // Remove API key\nAG.listKeys();                    // List all keys (masked)\n```\n\n### Cache\n```javascript\nAG.showCache();                   // Show cached responses\nAG.clearCache();                  // Clear all cached responses\n```\n\n### Fallback\n```javascript\nAG.setFallback('openai', 'anthropic');  // Set fallback provider\nAG.listFallbacks();                     // List all fallback providers\n```\n\n### Status\n```javascript\nAG.showStatus();                  // Full gateway status\n```\n\n## Security\n\n- API keys masked by default in console output\n- Circuit breaker prevents rapid retry cascades\n- Backoff strategy: 1s → 2s → 4s → 8s → 16s (exponential)\n- Max 5 retries per request\n- Cache expires after configurable TTL\n\n## Testing\n\n```bash\nnode tests/run-self-tests.js\n```\n\n### Test Coverage\n\n| Suite | Tests | Status |\n|---|---|---|\n| Self-tests (isolated) | 20 | ✅ Passing |\n\nFile v1.1.7:_meta.json\n\n{\n  \"ownerId\": \"kn7b6eyf5vc7khg5fr63pjm8xd82qvw5\",\n  \"slug\": \"api-proxy\",\n  \"version\": \"1.1.7\",\n  \"publishedAt\": 1785756120516\n}\n\nFile v1.1.7:skill-card.md\n\n## Description: <br>\nSmart proxy for external API calls with retry, caching, rate limiting, fallback providers, strict provider-domain allowlists, and disclosed local persistence of keys and request/cache metadata. <br>\n\nThis skill is ready for commercial/non-commercial use. <br>\n\n## Publisher: <br>\n[jlacroix82](https://clawhub.ai/user/jlacroix82) <br>\n\n### License/Terms of Use: <br>\nMIT-0 <br>\n\n\n## Use Case: <br>\nDevelopers and agents use api-gateway to route outbound HTTPS API calls through a local Node.js gateway that centralizes retries, rate-limit handling, caching, key lookup, and provider fallback. <br>\n\n### Deployment Geography for Use: <br>\nGlobal <br>\n\n## Known Risks and Mitigations: <br>\nRisk: The gateway handles API keys and may store them as plaintext local state. <br>\nMitigation: Prefer PROVIDER_API_KEY environment variables or a secrets manager, restrict workspace access, and review stored key files before use. <br>\nRisk: User-specified requests, prompts, headers, and bodies are sent to third-party API providers. <br>\nMitigation: Configure provider allowlists carefully, use dry runs for important calls, and send data only to trusted endpoints. <br>\nRisk: Cache and log files can persist request/cache data, especially when full response caching is enabled. <br>\nMitigation: Keep the default metadata-only cache for sensitive providers, avoid --cache-full for sensitive work, and clear cache/log files after use. <br>\n\n\n## Reference(s): <br>\n- [ClawHub skill page](https://clawhub.ai/jlacroix82/skills/api-proxy) <br>\n\n\n## Skill Output: <br>\n**Output Type(s):** [text, code, shell commands, configuration, guidance] <br>\n**Output Format:** [Markdown with inline shell commands and JSON examples] <br>\n**Output Parameters:** [1D] <br>\n**Other Properties Related to Output:** [Produces local gateway usage guidance and commands; actual API responses depend on user-configured providers.] <br>\n\n## Skill Version(s): <br>\n1.1.7 (source: server release metadata and clawhub.yaml) <br>\n\n## Ethical Considerations: <br>\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment. <br>\n\nFile v1.1.7:clawhub.yaml\n\nslug: api-proxy\nname: api-gateway\nowner: jlacroix82\ndescription: Smart proxy for external API calls with retry, caching, circuit breaker, and rate limiting. PERSISTS: API keys (chmod 0600 plaintext in keys.json), request/response cache metadata, and request logs. Network: outbound HTTPS only, with a strict provider-domain allowlist. Caches metadata by default; full response bodies are opt-in per provider. WARNING: Requests transmit prompts, request bodies, headers, and responses to third-party API providers. Keys apply allowlist to all sources (env-var or disk-stored).\nversion: 1.1.7\ntype: skill\nauthor: OpenClaw\nlicense: MIT\nkeywords:\n  - api\n  - proxy\n  - gateway\n  - circuit-breaker\n  - caching\n  - rate-limit\n  - allowlist\n  - security\ncapabilities:\n  - network\n  - filesystem\n  - environment\nentry: SKILL.md\ndependencies: []\npermissions:\n  - name: network.outbound\n    description: Outbound HTTPS to provider allowlist domains\n  - name: filesystem.read-write\n    description: Read/write data files in memory/api-gateway/ (keys.json chmod 0600)\n  - name: environment.read\n    description: Read PROVIDER_API_KEY environment variables\ndata_retention:\n  cache: 'metadata-only by default; full body opt-in per provider'\n  log: 'coarse: provider, status class, timestamp only — no endpoint paths or query strings stored'\n  keys: 'plaintext on disk with chmod 0600; env var override supported'\nsecurity_notes:\n  - 'WARNING: Requests transmit prompts, request bodies, headers, and responses to third-party API providers. Do not route sensitive/regulated data through the gateway.'\n  - 'Allowlist enforced for ALL keys (env-var and disk-stored) — both refuse auth if hostname not in allowlist'\n  - 'Keys stored as plain text in JSON with chmod 0600 (POSIX)'\n  - 'Request log stores only provider, status class, timestamp — no endpoint paths or query strings'\n  - 'For production, integrate with a secrets manager for API key storage'\n  - 'Use --call --dry-run before executing important calls'\n  - 'Clear logs/cache for sensitive work: --log --clear and --cache --clear'\n  - 'Masked output prevents accidental exposure in logs'\n\nArchive v1.1.6: 8 files, 20639 bytes\n\nFiles: api-gateway.js (32197b), clawhub.yaml (2136b), README.md (3137b), skill-card.md (2792b), SKILL.md (11431b), test/run-tests.js (3485b), tests/run-self-tests.js (6632b), _meta.json (128b)\n\nFile v1.1.6:SKILL.md\n\n---\nname: api-gateway\ndescription: Smart proxy for external API calls with retry, caching, rate limiting, and fallback providers. PERSISTS: API keys (chmod 0600 plaintext in keys.json), request/response cache metadata, and request logs. Network: outbound HTTPS only, with a strict provider-domain allowlist. Caches metadata by default; full response bodies are opt-in per provider.\n---\n\n# API Gateway ⚡\n\n> **Read this first.** This skill makes outbound HTTPS calls and writes plaintext API keys to disk. By installing or running it, you accept responsibility for the security of the keys you provide and the endpoints you target.\n\n**Stop duplicating API logic. Start routing through one smart gateway.**\n\n## What This Skill Does\n\nAPI Gateway is a local Node.js HTTP client wrapper that gives one call:\n\n- **Retry with exponential backoff** (3 attempts, 1s/2s/4s)\n- **Response caching** (default 5 min TTL, metadata-only)\n- **Rate-limit handling** (parses `x-ratelimit-remaining`, auto-fallback)\n- **Circuit breaker** (5-failure open, 30s cooldown, auto-recover)\n- **API key management** (masked display, chmod 0600 storage, env-var override)\n- **Fallback providers** (configurable per-provider chain)\n\n## ⚠️ Important Warnings\n\n### Outbound HTTPS Requests to Whitelisted Provider Domains\n`--call <provider> <endpoint>` sends HTTPS requests and, for configured providers, attaches a `Authorization: Bearer <key>` header. **The provider allowlist is strict: it is a domain-match check, not a `string.includes()` check.** A URL like `https://attacker.com/api?provider=openai` will NOT receive the key because the hostname must match the provider's registered allowlist entry. Review the allowlist in `--keys` output before adding sensitive keys.\n\n### API Keys Stored in Plaintext on Disk\nAPI keys saved via `--keys add` are written to `memory/api-gateway/keys.json` in plaintext, with file permissions set to `0600` (owner read/write only). The key is NEVER echoed back. Anyone with shell access to the workspace as the same user can still read it. For higher assurance, prefer environment variables: `OPENAI_API_KEY=sk-...` and pass `provider=env:OPENAI` to use the env var without disk storage.\n\n### Persistent Data Files (Disclosed Up Front)\nThe following files persist in `memory/api-gateway/` after any operation:\n- `keys.json` — API key storage, chmod 0600\n- `cache.json` — **Metadata-only by default** (status code, timestamp, headers, body length). Full response body caching is opt-in per provider via `--cache-full <provider>`.\n- `request-log.json` — Provider name, status class (2xx/4xx/5xx), timestamp. Endpoints and query strings are NOT stored.\n- `rate-limits.json` — Per-provider rate-limit state\n- `circuit-state.json` — Per-provider circuit-breaker state\n- `fallbacks.json` — Fallback provider mappings\n\nAll of these are intended, documented, and necessary for the skill's features. Default retention is unlimited unless cleared with `--cache --clear` and `--log --clear`.\n\n### Zero External Dependencies\nThis skill uses only Node.js built-ins (`http`, `https`, `fs`, `path`). There is no `package.json` to install, no transitive dependencies, no `npm install` step. The code you read is the code that runs.\n\n## Quick Start\n\n### Make an API call\n\n```bash\nnode skills/api-gateway/api-gateway.js --call openai https://api.openai.com/v1/chat/completions '{\"model\":\"gpt-4\",\"messages\":[{\"role\":\"user\",\"content\":\"hello\"}]}'\n```\n\nRetries up to 3 times with exponential backoff. Caches response **metadata** for 5 minutes.\n\n### Dry run (preview without executing)\n\n```bash\nnode skills/api-gateway/api-gateway.js --call --dry-run openai https://api.openai.com/v1/chat/completions\n```\n\n### Manage API keys\n\n```bash\n# List configured keys (masked, shows allowlist domains)\nnode skills/api-gateway/api-gateway.js --keys\n\n# Add a key (with provider allowlist)\nnode skills/api-gateway/api-gateway.js --keys add openai sk-abc123 --allow-domain api.openai.com\n\n# Remove a key\nnode skills/api-gateway/api-gateway.js --keys remove openai\n```\n\n### Use environment variables instead of stored keys (recommended for CI/ephemeral)\n\n```bash\nexport OPENAI_API_KEY=sk-abc123\nnode skills/api-gateway/api-gateway.js --call openai https://api.openai.com/v1/chat/completions '{\"model\":\"gpt-4\",\"messages\":[]}'\n```\n\nThe skill auto-detects `PROVIDER_API_KEY` env vars and uses them without disk storage. Stored keys take precedence if both are configured.\n\n### Cache, log, and rate status\n\n```bash\nnode skills/api-gateway/api-gateway.js --cache          # Show cache entries (metadata only)\nnode skills/api-gateway/api-gateway.js --cache --clear  # Clear cache\nnode skills/api-gateway/api-gateway.js --log            # Show request log (coarse: provider, status class, time)\nnode skills/api-gateway/api-gateway.js --log --clear    # Clear request log\nnode skills/api-gateway/api-gateway.js --rate openai    # Rate limit status\n```\n\n### Fallback providers and circuit breaker\n\n```bash\nnode skills/api-gateway/api-gateway.js --fallback openai anthropic\nnode skills/api-gateway/api-gateway.js --circuit --status\nnode skills/api-gateway/api-gateway.js --circuit openai --reset\n```\n\n### Status overview\n\n```bash\nnode skills/api-gateway/api-gateway.js --status\n```\n\n## Provider Allowlist (Security Boundary)\n\nThis is the most important section. The skill uses a **domain allowlist** to decide whether to inject the `Authorization: Bearer` header:\n\n- When you add a key with `--keys add <provider> <key> --allow-domain <domain>`, that domain is stored alongside the key.\n- On every call, the request URL's hostname is extracted and compared against the allowlist (exact match or `*.example.com` wildcard).\n- If the hostname does NOT match, the bearer token is omitted — the request still goes out, just without the key.\n- This means a malicious or mistyped endpoint URL cannot exfiltrate your key.\n\n**Example allowlist configurations:**\n\n```bash\n# Strict: only api.openai.com gets the OpenAI key\n--keys add openai sk-... --allow-domain api.openai.com\n\n# Wildcard: any *.anthropic.com endpoint\n--keys add anthropic sk-ant-... --allow-domain \"*.anthropic.com\"\n\n# Multi-domain (repeat flag)\n--keys add custom TOKEN --allow-domain api.example.com --allow-domain api-staging.example.com\n```\n\nIf you add a key WITHOUT `--allow-domain`, the key is still saved but the skill will **refuse to attach it to any request** until you add at least one allowlist entry. (You can edit `keys.json` to add `allowDomains: [\"api.openai.com\"]` directly.)\n\n## Features\n\n### Retry with Exponential Backoff\n- 3 retry attempts by default\n- Exponential backoff (1s, 2s, 4s)\n- All failures logged with attempt count\n\n### Response Caching (Metadata-Only by Default)\n- 5-minute TTL\n- Cache key = provider + endpoint + body hash\n- **Default behavior**: caches `{status, headers (redacted), timestamp, bodyLength}`. Body content is NOT stored.\n- **Opt-in full caching**: `--cache-full <provider>` enables full response body caching for that provider.\n- Auto-evicts expired entries\n- Cache hit detection prevents redundant calls\n\n### Rate Limit Handling\n- Tracks remaining requests from `x-ratelimit-remaining` headers\n- Auto-fallback when rate limited (if configured)\n- Status check via `--rate`\n\n### Key Management\n- Masked display (first 4 + last 4 chars)\n- Per-provider key storage in `memory/api-gateway/keys.json`\n- **chmod 0600** on the file (POSIX only; best-effort on Windows)\n- Environment-variable auto-detection (PROVIDER_API_KEY)\n- Allowlist attached to each key\n- Add/remove keys without exposing full values\n\n### Fallback Providers\n- Configurable per-provider fallback chain\n- Automatic failover on rate limit or error\n- No manual intervention needed\n\n### Circuit Breaker\n- Tracks failure rates per provider\n- Opens circuit after 5 consecutive failures\n- Auto-recovers after 30s cooldown (HALF-OPEN state)\n- Prevents cascading failures and saves API costs\n- CLI visibility: `--circuit --status` + `--circuit <name> --reset`\n\n## Configuration\n\nData files stored in: `memory/api-gateway/`\n\n- `keys.json` — API key storage (chmod 0600)\n- `fallbacks.json` — Fallback provider mappings\n- `cache.json` — Response cache (metadata-only by default)\n- `rate-limits.json` — Rate limit tracking\n- `request-log.json` — Request history (coarse: provider, status class, timestamp, NOT endpoints)\n- `circuit-state.json` — Circuit breaker state per provider\n\nOverride data directory:\n```bash\n--dir /path/to/data\n# or env var\nAPI_GATEWAY_DIR=/path/to/data node api-gateway.js --status\n```\n\n## Agent Protocol\n\nWhen making API calls:\n\n1. **Use the gateway** — `--call <provider> <endpoint> [body]` instead of direct fetch\n2. **Add keys with allowlist** — `--keys add <provider> <key> --allow-domain <domain>` before first use\n- **Prefer env vars in CI** — `PROVIDER_API_KEY` env vars bypass disk storage entirely. API Gateway auto-detects any `PROVIDER_API_KEY` environment variable (e.g. `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`) and uses it without disk storage. It does NOT read arbitrary environment variables — only the documented `PROVIDER_API_KEY` pattern — so unrelated secrets are never exposed to requests or local processing.\n4. **Set fallbacks** — `--fallback primary secondary` for critical providers\n5. **Check cache/log** — `--cache` / `--log` during heartbeats to monitor usage\n6. **Dry run** — `--call --dry-run` before executing important calls\n\n## Security Notes\n- Keys stored as plain text in JSON with chmod 0600 (POSIX)\n- For higher assurance, use environment variables (`PROVIDER_API_KEY`)\n- For production, integrate with a secrets manager\n- Masked output prevents accidental exposure in logs\n- Request log stores only provider + status class + timestamp (no endpoints)\n- Allowlist is a strict domain match, not a string contains\n- Code has zero external dependencies (no npm install)\n- ⚠️ **SENSITIVE DATA IN LOGS/CACHE:** request bodies, response headers, and endpoints you pass may themselves contain API keys, tokens, or prompts. The request log, `cache.json` (especially with `--cache-full`), and `request-log.json` persist this data to disk. Clear them after sensitive work (`--log --clear`, `--cache --clear`) and never call `--cache-full` for sensitive providers.\n- ⚠️ **HTTPS ONLY:** API Gateway refuses to send any request over plain HTTP (it would expose bearer credentials on the wire). Set `API_GATEWAY_ALLOW_HTTP=1` only for non-credential plaintext endpoints.\n\n## What This Skill Does NOT Do\n\n- Does NOT install npm packages\n- Does NOT auto-update or phone home\n- Does NOT read environment variables silently — only the documented `PROVIDER_API_KEY` pattern\n- Does NOT send Authorization headers to URLs outside the allowlist\n- Does NOT cache full response bodies unless explicitly opted in per provider\n- Does NOT log full endpoint URLs or query strings\n\n## Design Principles\n\n1. **Zero setup** — Works immediately, no config needed\n2. **No dependencies** — Pure Node.js http/https, no npm packages\n3. **Resilient** — Retry, fallback, and rate limit handling built in\n4. **Transparent** — Masked keys, cache status, request logging\n5. **Composable** — Works with any HTTP API, not just specific providers\n6. **Fail-closed on security boundaries** — If the allowlist doesn't match, the key is not sent. If a file permission can't be set, the call still proceeds but a warning is logged.\n\nFile v1.1.6:README.md\n\n# API Gateway\n\nSmart proxy for external API calls with retry logic, caching, circuit breaker, and rate limiting.\n\n## Features\n\n- **HTTP Proxy** — Make API calls with automatic retry and timeout handling\n- **Circuit Breaker** — Automatic failure detection and cooldown (opens after 5 failures)\n- **Response Caching** — Cache API responses to reduce repeated calls\n- **Rate Limiting** — Per-provider rate limit tracking\n- **Fallback Providers** — Configure fallback providers for redundancy\n- **API Key Management** — Store, list, and remove API keys with masked output\n- **Request Logging** — Track request history for debugging\n\n## Installation\n\n```bash\n# The skill is auto-loaded by OpenClaw via the skill registry.\n# For standalone use:\nconst AG = require('./api-gateway.js');\n```\n\n## Commands\n\n```\n--call <provider> <endpoint> [body]       Make API call with retry/caching\n--call --dry-run <provider> <endpoint>    Preview call without executing\n--keys                                     List configured API keys (masked)\n--keys add <provider> <key>               Add API key\n--keys remove <provider>                  Remove API key\n--cache                                    Show cache status\n--cache --clear                            Clear cache\n--rate <provider>                          Check rate limit status\n--fallback <provider> <fallback>           Set fallback provider\n--status                                   Gateway status overview\n```\n\n## API\n\n### `makeRequest(url, method, headers, body, timeout)`\nMake an HTTP request with automatic retry and timeout.\n\n```javascript\nconst result = await AG.makeRequest('https://api.openai.com/v1/models', 'GET', {}, null, 30000);\n```\n\n### `maskKey(key)`\nMask a sensitive key for display (`sk-a****fgh`).\n\n### Circuit Breaker\n```javascript\nAG.getCircuitState('openai');     // Current state (CLOSED/OPEN/HALF-OPEN)\nAG.recordFailure('openai');       // Record a failure\nAG.recordSuccess('openai');       // Record a success (resets counter)\nAG.getCircuitStatus();            // All circuit states\nAG.resetCircuit('openai');        // Reset circuit breaker\n```\n\n### Key Management\n```javascript\nAG.addKey('openai', 'sk-...');    // Add API key\nAG.removeKey('openai');           // Remove API key\nAG.listKeys();                    // List all keys (masked)\n```\n\n### Cache\n```javascript\nAG.showCache();                   // Show cached responses\nAG.clearCache();                  // Clear all cached responses\n```\n\n### Fallback\n```javascript\nAG.setFallback('openai', 'anthropic');  // Set fallback provider\nAG.listFallbacks();                     // List all fallback providers\n```\n\n### Status\n```javascript\nAG.showStatus();                  // Full gateway status\n```\n\n## Security\n\n- API keys masked by default in console output\n- Circuit breaker prevents rapid retry cascades\n- Backoff strategy: 1s → 2s → 4s → 8s → 16s (exponential)\n- Max 5 retries per request\n- Cache expires after configurable TTL\n\n## Testing\n\n```bash\nnode tests/run-self-tests.js\n```\n\n### Test Coverage\n\n| Suite | Tests | Status |\n|---|---|---|\n| Self-tests (isolated) | 20 | ✅ Passing |\n\nFile v1.1.6:_meta.json\n\n{\n  \"ownerId\": \"kn7b6eyf5vc7khg5fr63pjm8xd82qvw5\",\n  \"slug\": \"api-proxy\",\n  \"version\": \"1.1.6\",\n  \"publishedAt\": 1785725189063\n}\n\nFile v1.1.6:skill-card.md\n\n## Description: <br>\napi-gateway is a local smart proxy for external API calls with retry, caching, rate limiting, fallback providers, and API key management. <br>\n\nThis skill is ready for commercial/non-commercial use. <br>\n\n## Publisher: <br>\n[jlacroix82](https://clawhub.ai/user/jlacroix82) <br>\n\n### License/Terms of Use: <br>\nMIT-0 <br>\n\n\n## Use Case: <br>\nDevelopers and agent operators use this skill to route outbound HTTPS API calls through a local gateway that centralizes retries, rate-limit handling, caching, circuit breaking, fallback providers, and API key handling. <br>\n\n### Deployment Geography for Use: <br>\nGlobal <br>\n\n## Known Risks and Mitigations: <br>\nRisk: Local key and cache files can persist sensitive data, including plaintext API keys and cache keys derived from endpoint paths and request bodies; full-body caching can also persist complete provider responses. <br>\nMitigation: Prefer provider API keys from environment variables or a secrets manager, avoid routing regulated or proprietary prompts through the gateway, avoid full-body caching for sensitive providers, and clear cache and log files after sensitive work. <br>\nRisk: Outbound calls transmit prompts, request bodies, headers, and responses to third-party API providers. <br>\nMitigation: Use allowlisted provider domains, run dry runs before important calls, and only send data that is approved for the target provider. <br>\nRisk: The ClawHub security verdict is suspicious because the default cache behavior may retain more sensitive request metadata than the documentation suggests. <br>\nMitigation: Treat local cache files as sensitive, review cache contents and retention before deployment, and disable or regularly clear caching where request bodies or endpoint paths may contain secrets. <br>\n\n\n## Reference(s): <br>\n- [ClawHub skill page](https://clawhub.ai/jlacroix82/skills/api-proxy) <br>\n- [README.md](artifact/README.md) <br>\n- [SKILL.md](artifact/SKILL.md) <br>\n\n\n## Skill Output: <br>\n**Output Type(s):** [Shell commands, API Calls, JSON, Configuration, Guidance] <br>\n**Output Format:** [Markdown guidance with shell commands and JSON-like API responses or status output] <br>\n**Output Parameters:** [1D] <br>\n**Other Properties Related to Output:** [Writes local API key, cache, request log, rate-limit, circuit-breaker, and fallback state files under memory/api-gateway/ unless configured otherwise.] <br>\n\n## Skill Version(s): <br>\n1.1.6 (source: server release metadata and artifact/clawhub.yaml) <br>\n\n## Ethical Considerations: <br>\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment. <br>\n\nFile v1.1.6:clawhub.yaml\n\nslug: api-proxy\nname: api-gateway\nowner: jlacroix82\ndescription: Smart proxy for external API calls with retry, caching, circuit breaker, and rate limiting. PERSISTS: API keys (chmod 0600 plaintext in keys.json), request/response cache metadata, and request logs. Network: outbound HTTPS only, with a strict provider-domain allowlist. Caches metadata by default; full response bodies are opt-in per provider. WARNING: Requests transmit prompts, request bodies, headers, and responses to third-party API providers. Keys apply allowlist to all sources (env-var or disk-stored).\nversion: 1.1.6\ntype: skill\nauthor: OpenClaw\nlicense: MIT\nkeywords:\n  - api\n  - proxy\n  - gateway\n  - circuit-breaker\n  - caching\n  - rate-limit\n  - allowlist\n  - security\ncapabilities:\n  - network\n  - filesystem\n  - environment\nentry: SKILL.md\ndependencies: []\npermissions:\n  - name: network.outbound\n    description: Outbound HTTPS to provider allowlist domains\n  - name: filesystem.read-write\n    description: Read/write data files in memory/api-gateway/ (keys.json chmod 0600)\n  - name: environment.read\n    description: Read PROVIDER_API_KEY environment variables\ndata_retention:\n  cache: 'metadata-only by default; full body opt-in per provider'\n  log: 'coarse: provider, status class, timestamp only — no endpoint paths or query strings stored'\n  keys: 'plaintext on disk with chmod 0600; env var override supported'\nsecurity_notes:\n  - 'WARNING: Requests transmit prompts, request bodies, headers, and responses to third-party API providers. Do not route sensitive/regulated data through the gateway.'\n  - 'Allowlist enforced for ALL keys (env-var and disk-stored) — both refuse auth if hostname not in allowlist'\n  - 'Keys stored as plain text in JSON with chmod 0600 (POSIX)'\n  - 'Request log stores only provider, status class, timestamp — no endpoint paths or query strings'\n  - 'For production, integrate with a secrets manager for API key storage'\n  - 'Use --call --dry-run before executing important calls'\n  - 'Clear logs/cache for sensitive work: --log --clear and --cache --clear'\n  - 'Masked output prevents accidental exposure in logs'\n\nArchive v1.1.5: 8 files, 19863 bytes\n\nFiles: api-gateway.js (31424b), clawhub.yaml (2136b), README.md (3137b), skill-card.md (2344b), SKILL.md (10510b), test/run-tests.js (3485b), tests/run-self-tests.js (6632b), _meta.json (128b)\n\nFile v1.1.5:SKILL.md\n\n---\nname: api-gateway\ndescription: Smart proxy for external API calls with retry, caching, rate limiting, and fallback providers. PERSISTS: API keys (chmod 0600 plaintext in keys.json), request/response cache metadata, and request logs. Network: outbound HTTPS only, with a strict provider-domain allowlist. Caches metadata by default; full response bodies are opt-in per provider.\n---\n\n# API Gateway ⚡\n\n> **Read this first.** This skill makes outbound HTTPS calls and writes plaintext API keys to disk. By installing or running it, you accept responsibility for the security of the keys you provide and the endpoints you target.\n\n**Stop duplicating API logic. Start routing through one smart gateway.**\n\n## What This Skill Does\n\nAPI Gateway is a local Node.js HTTP client wrapper that gives one call:\n\n- **Retry with exponential backoff** (3 attempts, 1s/2s/4s)\n- **Response caching** (default 5 min TTL, metadata-only)\n- **Rate-limit handling** (parses `x-ratelimit-remaining`, auto-fallback)\n- **Circuit breaker** (5-failure open, 30s cooldown, auto-recover)\n- **API key management** (masked display, chmod 0600 storage, env-var override)\n- **Fallback providers** (configurable per-provider chain)\n\n## ⚠️ Important Warnings\n\n### Outbound HTTPS Requests to Whitelisted Provider Domains\n`--call <provider> <endpoint>` sends HTTPS requests and, for configured providers, attaches a `Authorization: Bearer <key>` header. **The provider allowlist is strict: it is a domain-match check, not a `string.includes()` check.** A URL like `https://attacker.com/api?provider=openai` will NOT receive the key because the hostname must match the provider's registered allowlist entry. Review the allowlist in `--keys` output before adding sensitive keys.\n\n### API Keys Stored in Plaintext on Disk\nAPI keys saved via `--keys add` are written to `memory/api-gateway/keys.json` in plaintext, with file permissions set to `0600` (owner read/write only). The key is NEVER echoed back. Anyone with shell access to the workspace as the same user can still read it. For higher assurance, prefer environment variables: `OPENAI_API_KEY=sk-...` and pass `provider=env:OPENAI` to use the env var without disk storage.\n\n### Persistent Data Files (Disclosed Up Front)\nThe following files persist in `memory/api-gateway/` after any operation:\n- `keys.json` — API key storage, chmod 0600\n- `cache.json` — **Metadata-only by default** (status code, timestamp, headers, body length). Full response body caching is opt-in per provider via `--cache-full <provider>`.\n- `request-log.json` — Provider name, status class (2xx/4xx/5xx), timestamp. Endpoints and query strings are NOT stored.\n- `rate-limits.json` — Per-provider rate-limit state\n- `circuit-state.json` — Per-provider circuit-breaker state\n- `fallbacks.json` — Fallback provider mappings\n\nAll of these are intended, documented, and necessary for the skill's features. Default retention is unlimited unless cleared with `--cache --clear` and `--log --clear`.\n\n### Zero External Dependencies\nThis skill uses only Node.js built-ins (`http`, `https`, `fs`, `path`). There is no `package.json` to install, no transitive dependencies, no `npm install` step. The code you read is the code that runs.\n\n## Quick Start\n\n### Make an API call\n\n```bash\nnode skills/api-gateway/api-gateway.js --call openai https://api.openai.com/v1/chat/completions '{\"model\":\"gpt-4\",\"messages\":[{\"role\":\"user\",\"content\":\"hello\"}]}'\n```\n\nRetries up to 3 times with exponential backoff. Caches response **metadata** for 5 minutes.\n\n### Dry run (preview without executing)\n\n```bash\nnode skills/api-gateway/api-gateway.js --call --dry-run openai https://api.openai.com/v1/chat/completions\n```\n\n### Manage API keys\n\n```bash\n# List configured keys (masked, shows allowlist domains)\nnode skills/api-gateway/api-gateway.js --keys\n\n# Add a key (with provider allowlist)\nnode skills/api-gateway/api-gateway.js --keys add openai sk-abc123 --allow-domain api.openai.com\n\n# Remove a key\nnode skills/api-gateway/api-gateway.js --keys remove openai\n```\n\n### Use environment variables instead of stored keys (recommended for CI/ephemeral)\n\n```bash\nexport OPENAI_API_KEY=sk-abc123\nnode skills/api-gateway/api-gateway.js --call openai https://api.openai.com/v1/chat/completions '{\"model\":\"gpt-4\",\"messages\":[]}'\n```\n\nThe skill auto-detects `PROVIDER_API_KEY` env vars and uses them without disk storage. Stored keys take precedence if both are configured.\n\n### Cache, log, and rate status\n\n```bash\nnode skills/api-gateway/api-gateway.js --cache          # Show cache entries (metadata only)\nnode skills/api-gateway/api-gateway.js --cache --clear  # Clear cache\nnode skills/api-gateway/api-gateway.js --log            # Show request log (coarse: provider, status class, time)\nnode skills/api-gateway/api-gateway.js --log --clear    # Clear request log\nnode skills/api-gateway/api-gateway.js --rate openai    # Rate limit status\n```\n\n### Fallback providers and circuit breaker\n\n```bash\nnode skills/api-gateway/api-gateway.js --fallback openai anthropic\nnode skills/api-gateway/api-gateway.js --circuit --status\nnode skills/api-gateway/api-gateway.js --circuit openai --reset\n```\n\n### Status overview\n\n```bash\nnode skills/api-gateway/api-gateway.js --status\n```\n\n## Provider Allowlist (Security Boundary)\n\nThis is the most important section. The skill uses a **domain allowlist** to decide whether to inject the `Authorization: Bearer` header:\n\n- When you add a key with `--keys add <provider> <key> --allow-domain <domain>`, that domain is stored alongside the key.\n- On every call, the request URL's hostname is extracted and compared against the allowlist (exact match or `*.example.com` wildcard).\n- If the hostname does NOT match, the bearer token is omitted — the request still goes out, just without the key.\n- This means a malicious or mistyped endpoint URL cannot exfiltrate your key.\n\n**Example allowlist configurations:**\n\n```bash\n# Strict: only api.openai.com gets the OpenAI key\n--keys add openai sk-... --allow-domain api.openai.com\n\n# Wildcard: any *.anthropic.com endpoint\n--keys add anthropic sk-ant-... --allow-domain \"*.anthropic.com\"\n\n# Multi-domain (repeat flag)\n--keys add custom TOKEN --allow-domain api.example.com --allow-domain api-staging.example.com\n```\n\nIf you add a key WITHOUT `--allow-domain`, the key is still saved but the skill will **refuse to attach it to any request** until you add at least one allowlist entry. (You can edit `keys.json` to add `allowDomains: [\"api.openai.com\"]` directly.)\n\n## Features\n\n### Retry with Exponential Backoff\n- 3 retry attempts by default\n- Exponential backoff (1s, 2s, 4s)\n- All failures logged with attempt count\n\n### Response Caching (Metadata-Only by Default)\n- 5-minute TTL\n- Cache key = provider + endpoint + body hash\n- **Default behavior**: caches `{status, headers (redacted), timestamp, bodyLength}`. Body content is NOT stored.\n- **Opt-in full caching**: `--cache-full <provider>` enables full response body caching for that provider.\n- Auto-evicts expired entries\n- Cache hit detection prevents redundant calls\n\n### Rate Limit Handling\n- Tracks remaining requests from `x-ratelimit-remaining` headers\n- Auto-fallback when rate limited (if configured)\n- Status check via `--rate`\n\n### Key Management\n- Masked display (first 4 + last 4 chars)\n- Per-provider key storage in `memory/api-gateway/keys.json`\n- **chmod 0600** on the file (POSIX only; best-effort on Windows)\n- Environment-variable auto-detection (PROVIDER_API_KEY)\n- Allowlist attached to each key\n- Add/remove keys without exposing full values\n\n### Fallback Providers\n- Configurable per-provider fallback chain\n- Automatic failover on rate limit or error\n- No manual intervention needed\n\n### Circuit Breaker\n- Tracks failure rates per provider\n- Opens circuit after 5 consecutive failures\n- Auto-recovers after 30s cooldown (HALF-OPEN state)\n- Prevents cascading failures and saves API costs\n- CLI visibility: `--circuit --status` + `--circuit <name> --reset`\n\n## Configuration\n\nData files stored in: `memory/api-gateway/`\n\n- `keys.json` — API key storage (chmod 0600)\n- `fallbacks.json` — Fallback provider mappings\n- `cache.json` — Response cache (metadata-only by default)\n- `rate-limits.json` — Rate limit tracking\n- `request-log.json` — Request history (coarse: provider, status class, timestamp, NOT endpoints)\n- `circuit-state.json` — Circuit breaker state per provider\n\nOverride data directory:\n```bash\n--dir /path/to/data\n# or env var\nAPI_GATEWAY_DIR=/path/to/data node api-gateway.js --status\n```\n\n## Agent Protocol\n\nWhen making API calls:\n\n1. **Use the gateway** — `--call <provider> <endpoint> [body]` instead of direct fetch\n2. **Add keys with allowlist** — `--keys add <provider> <key> --allow-domain <domain>` before first use\n3. **Prefer env vars in CI** — `PROVIDER_API_KEY` env vars bypass disk storage entirely\n4. **Set fallbacks** — `--fallback primary secondary` for critical providers\n5. **Check cache/log** — `--cache` / `--log` during heartbeats to monitor usage\n6. **Dry run** — `--call --dry-run` before executing important calls\n\n## Security Notes\n\n- Keys stored as plain text in JSON with chmod 0600 (POSIX)\n- For higher assurance, use environment variables (`PROVIDER_API_KEY`)\n- For production, integrate with a secrets manager\n- Masked output prevents accidental exposure in logs\n- Request log stores only provider + status class + timestamp (no endpoints)\n- Allowlist is a strict domain match, not a string contains\n- Code has zero external dependencies (no npm install)\n\n## What This Skill Does NOT Do\n\n- Does NOT install npm packages\n- Does NOT auto-update or phone home\n- Does NOT read environment variables silently — only the documented `PROVIDER_API_KEY` pattern\n- Does NOT send Authorization headers to URLs outside the allowlist\n- Does NOT cache full response bodies unless explicitly opted in per provider\n- Does NOT log full endpoint URLs or query strings\n\n## Design Principles\n\n1. **Zero setup** — Works immediately, no config needed\n2. **No dependencies** — Pure Node.js http/https, no npm packages\n3. **Resilient** — Retry, fallback, and rate limit handling built in\n4. **Transparent** — Masked keys, cache status, request logging\n5. **Composable** — Works with any HTTP API, not just specific providers\n6. **Fail-closed on security boundaries** — If the allowlist doesn't match, the key is not sent. If a file permission can't be set, the call still proceeds but a warning is logged.\n\nFile v1.1.5:README.md\n\n# API Gateway\n\nSmart proxy for external API calls with retry logic, caching, circuit breaker, and rate limiting.\n\n## Features\n\n- **HTTP Proxy** — Make API calls with automatic retry and timeout handling\n- **Circuit Breaker** — Automatic failure detection and cooldown (opens after 5 failures)\n- **Response Caching** — Cache API responses to reduce repeated calls\n- **Rate Limiting** — Per-provider rate limit tracking\n- **Fallback Providers** — Configure fallback providers for redundancy\n- **API Key Management** — Store, list, and remove API keys with masked output\n- **Request Logging** — Track request history for debugging\n\n## Installation\n\n```bash\n# The skill is auto-loaded by OpenClaw via the skill registry.\n# For standalone u\n\nArchive v1.1.4: 8 files, 19468 bytes\n\nFiles: api-gateway.js (30612b), clawhub.yaml (2136b), README.md (3137b), skill-card.md (2117b), SKILL.md (10510b), test/run-tests.js (3485b), tests/run-self-tests.js (6632b), _meta.json (128b)\n\nArchive v1.1.3: 8 files, 19383 bytes\n\nFiles: api-gateway.js (30494b), clawhub.yaml (1208b), README.md (3137b), skill-card.md (2886b), SKILL.md (10510b), test/run-tests.js (3485b), tests/run-self-tests.js (6632b), _meta.json (128b)\n\nArchive v1.1.2: 8 files, 13368 bytes\n\nFiles: api-gateway.js (18043b), clawhub.yaml (450b), README.md (3137b), skill-card.md (2297b), SKILL.md (5923b), test/run-tests.js (3485b), tests/run-self-tests.js (6632b), _meta.json (128b)","readmeExcerpt":"Skill: api-gateway Owner: jlacroix82 Summary: Smart proxy for external API calls with retry, caching, rate limiting, and fallback providers. Key management with masked display. Zero external dependencies. Tags: latest:1.1.8, security-fix:1.1.0 Version history: v1.1.12 | 2026-09-13T12:34:51.177Z | auto **api-proxy 1.1.12** - Cache and rate-limit keys are now SHA-256 digests; endpoint URLs and request bodies are no lon","codeSnippets":[],"executableExamples":[{"language":"bash","snippet":"node skills/api-gateway/api-gateway.js --call openai https://api.openai.com/v1/chat/completions '{\"model\":\"gpt-4\",\"messages\":[{\"role\":\"user\",\"content\":\"hello\"}]}'"},{"language":"bash","snippet":"node skills/api-gateway/api-gateway.js --call --dry-run openai https://api.openai.com/v1/chat/completions"},{"language":"bash","snippet":"# List configured keys (masked, shows allowlist domains)\nnode skills/api-gateway/api-gateway.js --keys\n\n# Add a key (with provider allowlist)\nnode skills/api-gateway/api-gateway.js --keys add openai sk-abc123 --allow-domain api.openai.com\n\n# Remove a key\nnode skills/api-gateway/api-gateway.js --keys remove openai"},{"language":"bash","snippet":"export OPENAI_API_KEY=sk-abc123\nnode skills/api-gateway/api-gateway.js --call openai https://api.openai.com/v1/chat/completions '{\"model\":\"gpt-4\",\"messages\":[]}'"},{"language":"bash","snippet":"node skills/api-gateway/api-gateway.js --cache          # Show cache entries (metadata only)\nnode skills/api-gateway/api-gateway.js --cache --clear  # Clear cache\nnode skills/api-gateway/api-gateway.js --log            # Show request log (coarse: provider, status class, time)\nnode skills/api-gateway/api-gateway.js --log --clear    # Clear request log\nnode skills/api-gateway/api-gateway.js --rate openai    # Rate limit status"},{"language":"bash","snippet":"node skills/api-gateway/api-gateway.js --fallback openai anthropic\nnode skills/api-gateway/api-gateway.js --circuit --status\nnode skills/api-gateway/api-gateway.js --circuit openai --reset"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\nname: api-gateway\nversion: 1.1.12\ndescription: Smart proxy for external API calls with retry, caching, rate limiting, and fallback providers. PERSISTS: API keys (chmod 0600 plaintext in keys.json), request/response cache metadata, and request logs. Network: outbound HTTPS only, with a strict provider-domain allowlist. Caches metadata by default; full response bodies are opt-in per provider. Cache and rate-limit keys are SHA-256 digests, so request bodies and endpoint URLs are never written to disk in plaintext.\n---\n\n# API Gateway ⚡\n\n> **Read this first.** This skill makes outbound HTTPS calls and writes plaintext API keys to disk. By installing or running it, you accept responsibility for the security of the keys you provide and the endpoints you target.\n\n**Stop duplicating API logic. Start routing through one smart gateway.**\n\n## What This Skill Does\n\nAPI Gateway is a local Node.js HTTP client wrapper that gives one call:\n\n- **Retry with exponential backoff** (3 attempts, 1s/2s/4s)\n- **Response caching** (default 5 min TTL, metadata-only)\n- **Rate-limit handling** (parses `x-ratelimit-remaining`, auto-fallback)\n- **Circuit breaker** (5-failure open, 30s cooldown, auto-recover)\n- **API key management** (masked display, chmod 0600 storage, env-var override)\n- **Fallback providers** (configurable per-provider chain)\n\n## ⚠️ Important Warnings\n\n### Outbound HTTPS Requests to Whitelisted Provider Domains\n`--call <provider> <endpoint>` sends HTTPS requests and, for configured providers, attaches a `Authorization: Bearer <key>` header. **The provider allowlist is strict: it is a domain-match check, not a `string.includes()` check.** A URL like `https://attacker.com/api?provider=openai` will NOT receive the key because the hostname must match the provider's registered allowlist entry. Review the allowlist in `--keys` output before adding sensitive keys.\n\n### API Keys Stored in Plaintext on Disk\nAPI keys saved via `--keys add` are written to `memory/api-gateway/keys.json` in plaintext, with file permissions set to `0600` (owner read/write only). The key is NEVER echoed back. Anyone with shell access to the workspace as the same user can still read it. For higher assurance, prefer environment variables: `OPENAI_API_KEY=sk-...` — API Gateway auto-detects any `PROVIDER_API_KEY` variable (e.g. `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`) and uses it without disk storage. It does NOT read arbitrary `env:NAME` references — only the `PROVIDER_API_KEY` pattern — so unrelated secrets are never pulled in.\n\n### Persistent Data Files (Disclosed Up Front)\nThe following files persist in `memory/api-gateway/` after any operation:\n- `keys.json` — API key storage, chmod 0600\n- `cache.json` — **Metadata-only by default** (status code, timestamp, response headers, response body *length*). The full response **body** is NOT stored unless you explicitly enable it per provider via `--cache-full <provider>`. **Cache keys are provider name + a SHA-256 digest of the endpoint path an"},{"path":"README.md","content":"# API Gateway\n\nSmart proxy for external API calls with retry logic, caching, circuit breaker, and rate limiting.\n\n> ⚠️ **DATA LEAVES TO A THIRD PARTY:** every `--call` sends your request (URL, headers, body, prompts) to the provider endpoint *you* specify — a separate external service. Responses come back from that provider and may be retained by them per their own policy. This skill is NOT a transparent pass-through; it centralizes collection, storage, and forwarding of potentially sensitive data. Only call endpoints you trust. By default only request **metadata** (provider, status class, timestamp) and cache **metadata** are written to disk; the full response body is written only if you enable `--cache-full <provider>`. Cache and rate-limit entries are keyed by a SHA-256 digest of the endpoint path and request body, so neither your endpoints nor your payloads are stored on disk in readable form.\n\n## Features\n\n- **HTTP Proxy** — Make API calls with automatic retry and timeout handling\n- **Circuit Breaker** — Automatic failure detection and cooldown (opens after 5 failures)\n- **Response Caching** — Cache API responses to reduce repeated calls\n- **Rate Limiting** — Per-provider rate limit tracking\n- **Fallback Providers** — Configure fallback providers for redundancy\n- **API Key Management** — Store, list, and remove API keys with masked output\n- **Request Logging** — Track request history for debugging\n\n## Installation\n\n```bash\n# The skill is auto-loaded by OpenClaw via the skill registry.\n# For standalone use:\nconst AG = require('./api-gateway.js');\n```\n\n## Commands\n\n```\n--call <provider> <endpoint> [body]       Make API call with retry/caching\n--call --dry-run <provider> <endpoint>    Preview call without executing\n--keys                                     List configured API keys (masked)\n--keys add <provider> <key>               Add API key\n--keys remove <provider>                  Remove API key\n--cache                                    Show cache status\n--cache --clear                            Clear cache\n--rate <provider>                          Check rate limit status\n--fallback <provider> <fallback>           Set fallback provider\n--status                                   Gateway status overview\n```\n\n## API\n\n### `makeRequest(url, method, headers, body, timeout)`\nMake an HTTP request with automatic retry and timeout.\n\n```javascript\nconst result = await AG.makeRequest('https://api.openai.com/v1/models', 'GET', {}, null, 30000);\n```\n\n### `maskKey(key)`\nMask a sensitive key for display (`sk-a****fgh`).\n\n### Circuit Breaker\n```javascript\nAG.getCircuitState('openai');     // Current state (CLOSED/OPEN/HALF-OPEN)\nAG.recordFailure('openai');       // Record a failure\nAG.recordSuccess('openai');       // Record a success (resets counter)\nAG.getCircuitStatus();            // All circuit states\nAG.resetCircuit('openai');        // Reset circuit breaker\n```\n\n### Key Management\n```javascript\nAG.addKey('openai', 'sk-...');    // Add API key\nAG.r"},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn7b6eyf5vc7khg5fr63pjm8xd82qvw5\",\n  \"slug\": \"api-proxy\",\n  \"version\": \"1.1.12\",\n  \"publishedAt\": 1789302891177\n}"},{"path":"skill-card.md","content":"## Description:\n\nAPI Gateway is a local Node.js proxy for outbound API calls with retries, metadata-only caching by default, rate-limit handling, circuit breaking, fallback providers, and API key management.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[jlacroix82](https://clawhub.ai/user/jlacroix82)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and agents use this skill to centralize outbound HTTP API calls through a reusable gateway with retry, fallback, rate-limit, cache, request-log, and API-key handling controls.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The gateway handles provider credentials and can store API keys as plaintext in the local workspace.\n\nMitigation: Prefer PROVIDER_API_KEY environment variables or a secrets manager, use tightly scoped allowlisted stored keys only when needed, and remove local keys after sensitive work.\n\nRisk: Requests, prompts, headers, bodies, and responses are transmitted to the third-party provider endpoint selected by the caller.\n\nMitigation: Send requests only to trusted endpoints, review provider retention policies, and avoid routing sensitive or regulated data through untrusted providers.\n\nRisk: Full-body caching can persist complete responses that may contain secrets, personal data, or proprietary content.\n\nMitigation: Keep the default metadata-only cache, avoid --cache-full for sensitive providers, and clear cache and log files after sensitive sessions.\n\nRisk: Plain HTTP can expose traffic when API_GATEWAY_ALLOW_HTTP=1 is enabled.\n\nMitigation: Use HTTPS endpoints and never enable API_GATEWAY_ALLOW_HTTP=1 when credentials or sensitive payloads may be attached.\n\n## Reference(s):\n\n- [ClawHub skill page](https://clawhub.ai/jlacroix82/skills/api-proxy)\n- [README](README.md)\n- [Vetting report](VET-REPORT.md)\n\n## Skill Output:\n\n**Output Type(s):** [text, shell commands, configuration, guidance]\n\n**Output Format:** [CLI text, JSON API responses, and Markdown guidance]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [May perform outbound HTTP API calls and write local gateway state, including keys, cache metadata, request logs, rate-limit state, circuit state, and fallback mappings.]\n\n## Skill Version(s):\n\n1.1.12 (source: frontmatter and server release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment."},{"path":"VET-REPORT.md","content":"# Vetting Report: api-proxy\n**Date:** 2026-09-13 08:11 EDT\n**Vetter:** JARVIS (skill-vetter skill)\n**Source:** local (/home/jarvis/.openclaw/workspace)\n**Verdict:** PASS\n**Risk score:** 8/100\n\n## Findings\n\n### Critical\n- (none)\n\n### Warnings\n- 2 network URLs\n- No description in frontmatter\n\n### Notes\n- (none)\n\n## Permission footprint\n- Tools requested: exec process read write \n\n## Network footprint\nhttps://api.openai.com/v1/chat/completion\nhttps://attacker.com/api?provider=openai` will NOT receive the key becau\n\n## Side effects\n- Reads: SKILL.md\n- Writes: VET-REPORT.md (this file)\n- Network: 2 distinct hosts\n\n## Verdict rationale\nScore 8/100 with 0 critical findings and 2 warnings."}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":null,"editorialQuality":{"score":100,"threshold":65,"status":"thin","wordCount":1931,"uniquenessScore":39,"reasons":["uniqueness-below-45"]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-10T12:24:36.329Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-10T12:24:36.329Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-10T14:42:50.672Z","emptyReason":null},"items":[{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}