npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

openclaw-cc-gateway

v0.2.0

Published

Multi-tenant Claude Code CLI gateway for OpenClaw with auto-discovery

Readme

OpenClaw CC Gateway

GitHub stars GitHub license English | 中文

Multi-tenant Claude Code CLI gateway for OpenClaw. Bypasses Anthropic's third-party OAuth restrictions by routing LLM requests through the Claude Code CLI subprocess, with per-tenant skill and session isolation.

Features

  • Anthropic Messages API (/v1/messages) — native format that OpenClaw uses
  • OpenAI Chat API (/v1/chat/completions) — compatibility endpoint
  • Multi-tenant isolation — per-tenant API keys, sessions, skills, env vars, and concurrency control
  • Auto-discovery — automatically finds Docker and local OpenClaw instances
  • Auto-setup — generates config, syncs skills, extracts env vars in one command
  • Per-tenant Skills — each tenant loads only its own OpenClaw skills (skills/<tenant>/)
  • Per-tenant Env Vars — auto-extracted from each OpenClaw instance's openclaw.json
  • OpenClaw Skill Prompt — teaches Claude CLI to use openclaw commands (cron, messaging, etc.)
  • Multi-turn buffering — CLI executes tools internally, only the final response is returned
  • Streaming SSE — full Anthropic streaming event passthrough

How It Works

OpenClaw Container (tenant=alice)
  → POST /v1/messages (x-api-key: alice-key)
    → openclaw-cc-gateway
      → authenticate → tenant=alice
      → inject env vars from config.tenants[alice].env
      → load skills from skills/alice/
      → spawn claude CLI subprocess
        → Claude Max subscription (bypasses OAuth restrictions)
      → buffer tool rounds, return final response
    ← Anthropic SSE stream
  ← Agent processes response

Quick Start

Prerequisites

  • Node.js 22+
  • Claude Code CLI: npm install -g @anthropic-ai/claude-code && claude auth login
  • Docker (if using OpenClaw in containers)

Install & Setup

git clone <repo-url>
cd openclaw-cc-gateway
npm install
npm run build

# Auto-discover OpenClaw instances, generate config, sync skills
node dist/index.js --setup

This will:

  1. Detect Docker host IP
  2. Discover all running OpenClaw containers
  3. Extract env vars from each instance's openclaw.json
  4. Generate config.yaml with API keys and env vars per tenant
  5. Update each instance's openclaw.json to point to the gateway
  6. Sync skills per tenant (skills/<tenant>/)

Use --no-skills to skip skill sync, or --skills to re-sync skills only.

Start

npm start

# Or with PM2
pm2 start dist/index.js --name openclaw-cc-gateway
pm2 save

Tenant Management

# List all tenants
npm run manage list

# Add a new tenant (auto-generates API key)
npm run manage add <name>
npm run manage add <name> --apply        # add + apply to OpenClaw instance

# Remove a tenant
npm run manage remove <name>

# Push config to OpenClaw instance(s)
npm run manage apply                     # all tenants
npm run manage apply <name>              # single tenant

# Generate a random API key
npm run manage gen-key

The apply command updates:

  • Instance's openclaw.json (model provider baseUrl + apiKey)
  • Instance's .env file (ANTHROPIC_BASE_URL + ANTHROPIC_API_KEY)

Skill Management

Skills are synced per-tenant with bidirectional support — each OpenClaw instance gets its own isolated skill directory. When a CLI subprocess runs for a tenant, it only loads skills from skills/<tenant>/.

# List skills from OpenClaw instance(s)
npm run manage skills list               # all tenants
npm run manage skills list <name>        # single tenant

# Pull: OpenClaw → local (download skills from containers)
npm run manage skills pull               # all tenants
npm run manage skills pull <name>        # single tenant

# Push: local → OpenClaw (upload skills to containers)
npm run manage skills push               # all tenants
npm run manage skills push <name>        # single tenant

# Diff: show what's different between local and remote
npm run manage skills diff               # all tenants
npm run manage skills diff <name>        # single tenant

# Bidirectional sync: pull new remote + push new local
npm run manage skills bisync             # all tenants
npm run manage skills bisync <name>      # single tenant
npm run manage skills bisync --pull      # only pull direction
npm run manage skills bisync --push      # only push direction

# Clean synced skills
npm run manage skills clean

Sync Directions

| Command | Direction | What it does | |---------|-----------|-------------| | pull | OpenClaw → local | Download skills from container to skills/<tenant>/ | | push | local → OpenClaw | Upload skills from skills/<tenant>/ to container's workspace/skills/ | | diff | — | Show which skills exist only locally, only remotely, or both | | bisync | both | Pull new remote skills + push new local skills (no overwrites) |

Skill Isolation

skills/
├── alice/                 ← only loaded for tenant "alice"
│   ├── github/SKILL.md
│   ├── custom-tool/
│   └── ...
├── bob/                   ← only loaded for tenant "bob"
│   ├── github/SKILL.md
│   ├── another-skill/
│   └── ...
└── ...

Each tenant's CLI subprocess receives --add-dir skills/<tenant>/<skill> for its skills only. Skills from other tenants are never loaded.

Configuration

config.yaml

Auto-generated by --setup, or create manually from config.example.yaml:

server:
  port: 3456
  host: "0.0.0.0"
  docker_host_ip: "auto"           # auto-detected, or set DOCKER_HOST_IP env

cli:
  bin: "claude"
  timeout: 900000                   # 15 min per request
  max_concurrent: 3                 # max parallel CLI subprocesses

session:
  ttl: 3600
  cleanup_interval: 900

skills:
  sync: "auto"                     # auto | manual | disabled
  dir: "./skills"                  # per-tenant skill storage

tenants:
  - name: alice
    api_key: "<hex-string>"
    env:                           # auto-extracted from openclaw.json
      MY_API_KEY: "xxx"
      MY_SECRET: "xxx"
  - name: bob
    api_key: "<hex-string>"

Per-Tenant Isolation

| Resource | Isolation | |----------|-----------| | API Key | Unique per tenant | | Sessions | Namespaced <tenant>:<conversationId> | | Skills | skills/<tenant>/ directory | | Env Vars | Injected into CLI subprocess from config.tenants[].env | | Concurrency | Fair queuing, max 1 concurrent per tenant | | OpenClaw Skill | <!-- openclaw-tenant: NAME --> routes to correct container |

Environment Variables

| Variable | Description | Default | |----------|-------------|---------| | PORT | Gateway port | 3456 | | HOST | Bind address | 0.0.0.0 | | DOCKER_HOST_IP | Docker host IP for containers | auto-detect | | CLAUDE_BIN | Claude CLI path | claude | | CLI_TIMEOUT | Request timeout (ms) | 900000 | | MAX_CONCURRENT | Max concurrent CLI processes | 3 |

API Endpoints

POST /v1/messages (Anthropic)

curl -X POST http://localhost:3456/v1/messages \
  -H "x-api-key: <tenant-key>" \
  -H "content-type: application/json" \
  -H "anthropic-version: 2023-06-01" \
  -d '{"model":"claude-sonnet-4","max_tokens":1024,"stream":true,"messages":[{"role":"user","content":"Hello"}]}'

POST /v1/chat/completions (OpenAI)

curl -X POST http://localhost:3456/v1/chat/completions \
  -H "Authorization: Bearer <tenant-key>" \
  -H "content-type: application/json" \
  -d '{"model":"claude-sonnet-4","messages":[{"role":"user","content":"Hello"}]}'

GET /health

Returns gateway status, tenant list, and queue stats.

GET /v1/models

Lists available models.

OpenClaw Skill Prompt

The gateway injects openclaw-skill.md as a system prompt, teaching the Claude CLI how to execute OpenClaw operations. The skill auto-detects Docker vs local mode and routes commands to the correct container based on the <!-- openclaw-tenant: NAME --> context tag.

| Category | Commands | |----------|----------| | Cron/Scheduling | cron add/rm/edit/enable/disable/run/list/status | | Messaging | message send/read/broadcast/react/pin/poll | | Agents | agent/agents list/add/bind/delete | | Sessions | sessions list/cleanup | | Memory | memory search/status/index | | Models | models list/status/set | | Channels | channels list/status | | Nodes | nodes status/notify/camera/screen/invoke | | Directory | directory self/peers/groups | | Skills | skills list/info/check | | Config | config get/set/unset/validate | | System | health/status/doctor/heartbeat |

Architecture

                        ┌──────────────────────────────────────┐
                        │  openclaw-cc-gateway (:3456)          │
                        │                                       │
                        │  ┌─ Auth (per-tenant API key)         │
  OpenClaw instances    │  ├─ Queue (concurrency control)       │
  ┌──────────────┐      │  ├─ Session (per-tenant namespace)    │  ┌──────────┐
  │ tenant-a     │─────▶│  ├─ Env (per-tenant injection)        │──│ Claude   │
  │ tenant-b     │─────▶│  ├─ Skills (per-tenant directory)     │  │ CLI      │
  │ tenant-c     │─────▶│  └─ CLI subprocess (claude --print)   │  │ (Max)    │
  │ ...          │─────▶│     + --add-dir skills/<tenant>/*     │  └──────────┘
  └──────────────┘      │     + env vars from tenant config     │
                        │     + openclaw-skill.md injection      │
                        └──────────────────────────────────────┘

Multi-turn Tool Handling

When the CLI uses tools internally (Bash, Read, etc.), it produces multiple message rounds. The gateway buffers intermediate tool-use rounds and only forwards the final end_turn response to the client, preventing pi-ai SDK "Unexpected event order" errors.

License

MIT