Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsCommunityBlog
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

Back to skills

Openilink Hub Wechat Bot

FSecurity

> Skill by [ara.so](https://ara.so) — Daily 2026 Skills collection. OpeniLink Hub is an open-source self-hosted platform for managing WeChat bots via the official **iLink (智联) protocol** introduced with WeChat ClawBot in March 2026. It handles context_token lifecycle, CDN encryption, 24-hour session renewal, multi-bot management, and message dispatch — so you focus on your business logic.

81 stars
0 votes
0 copies
0 views
Added 9/19/2026
developmentjavascriptpythongojavabashsqlreactnodeexpressdocker

Works with

terminalcliapi

Security Analysis

F26/100
criticalPipes output to a shell interpreter
mediumUses curl or wget to download content
criticalDownloads and executes remote scripts — classic supply chain attack
mediumInstalls packages at runtime which could introduce malicious dependencies
mediumInstalls packages at runtime which could introduce malicious dependencies

Scanned 9/19/2026

Install to Claude Code

$npx -y skills add reason-machines/trending-skills --skill openilink-hub-wechat-bot --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Openilink Hub Wechat Bot?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Openilink Hub Wechat Bot
[![Security: F — Skills Directory](https://www.skillsdirectory.com/api/skills/reason-machines-openilink-hub-wechat-bot/badge)](https://www.skillsdirectory.com/skills/reason-machines-openilink-hub-wechat-bot)

More formats (shields.io, HTML) on the badges page.

Download Zip
Files
SKILL.md
```markdown
---
name: openilink-hub-wechat-bot
description: Self-hosted WeChat Bot management platform using iLink protocol with WebSocket/Webhook/AI relay, App Marketplace, and 7-language SDKs
triggers:
  - set up openilink hub for wechat bot management
  - integrate wechat messages with webhook or websocket
  - build an openilink app for wechat automation
  - configure ai auto-reply for wechat bot
  - deploy openilink hub with docker
  - use openilink sdk to send wechat messages
  - create custom app for openilink marketplace
  - forward wechat messages to slack or feishu
---

# OpeniLink Hub — WeChat Bot Management Platform

> Skill by [ara.so](https://ara.so) — Daily 2026 Skills collection.

OpeniLink Hub is an open-source self-hosted platform for managing WeChat bots via the official **iLink (智联) protocol** introduced with WeChat ClawBot in March 2026. It handles context_token lifecycle, CDN encryption, 24-hour session renewal, multi-bot management, and message dispatch — so you focus on your business logic.

## Installation

### One-line install (Linux/macOS)
```bash
curl -fsSL https://raw.githubusercontent.com/openilink/openilink-hub/main/install.sh | sh
oih
```

### Docker (quickstart)
```bash
docker run -d -p 9800:9800 ghcr.io/openilink/openilink-hub:latest
```

### Docker Compose (production with PostgreSQL)
```yaml
# docker-compose.yml
services:
  postgres:
    image: postgres:17-alpine
    environment:
      POSTGRES_USER: openilink
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: openilink
    volumes:
      - pgdata:/var/lib/postgresql/data

  hub:
    image: ghcr.io/openilink/openilink-hub:latest
    ports:
      - "9800:9800"
    environment:
      DATABASE_URL: postgres://openilink:${POSTGRES_PASSWORD}@postgres:5432/openilink?sslmode=disable
      RP_ORIGIN: https://hub.example.com
      RP_ID: hub.example.com
      SECRET: ${HUB_SECRET}
    depends_on:
      - postgres

volumes:
  pgdata:
```

```bash
docker compose up -d
```

### Build from source
```bash
git clone https://github.com/openilink/openilink-hub.git
cd openilink-hub
cd web && pnpm install && pnpm run build && cd ..
go build -o oih .
./oih
```

## CLI Commands

| Command | Description |
|---------|-------------|
| `oih` | Run in foreground |
| `oih install` | Register as systemd (Linux) or launchd (macOS) service |
| `oih uninstall` | Remove system service |
| `oih version` | Show version |

## Environment Variables

| Variable | Default | Description |
|----------|---------|-------------|
| `DATABASE_URL` | SQLite (auto) | `postgres://user:pass@host/db?sslmode=disable` |
| `SECRET` | — | Random string for signing tokens |
| `RP_ORIGIN` | `http://localhost:9800` | WebAuthn relying party origin (full URL) |
| `RP_ID` | `localhost` | WebAuthn relying party ID (domain only) |
| `PORT` | `9800` | HTTP server port |

**SQLite data locations:**
- Linux: `~/.local/share/openilink-hub/openilink.db`
- macOS: `~/Library/Application Support/openilink-hub/openilink.db`
- root/service: `/var/lib/openilink-hub/openilink.db`

## SDK Usage

### Go SDK
```bash
go get github.com/openilink/openilink-sdk-go
```

```go
package main

import (
    "context"
    "fmt"
    "log"

    openilink "github.com/openilink/openilink-sdk-go"
)

func main() {
    client := openilink.NewClient(openilink.Config{
        HubURL: "http://localhost:9800",
        Token:  os.Getenv("OPENILINK_TOKEN"),
    })

    // Listen for incoming messages via WebSocket
    err := client.OnMessage(context.Background(), func(msg *openilink.Message) error {
        fmt.Printf("[%s] %s: %s\n", msg.BotID, msg.Sender, msg.Content)

        // Reply to the message
        return client.SendText(context.Background(), &openilink.SendTextRequest{
            BotID:    msg.BotID,
            ToUserID: msg.Sender,
            Content:  "收到你的消息: " + msg.Content,
        })
    })
    if err != nil {
        log.Fatal(err)
    }
}
```

### Node.js SDK
```bash
npm install @openilink/openilink-sdk-node
```

```javascript
import { OpeniLinkClient } from '@openilink/openilink-sdk-node';

const client = new OpeniLinkClient({
  hubUrl: 'http://localhost:9800',
  token: process.env.OPENILINK_TOKEN,
});

// Subscribe to messages
client.onMessage(async (msg) => {
  console.log(`[${msg.botId}] ${msg.sender}: ${msg.content}`);

  // Send a reply
  await client.sendText({
    botId: msg.botId,
    toUserId: msg.sender,
    content: `Echo: ${msg.content}`,
  });
});

await client.connect();
```

### Python SDK
```bash
pip install openilink-sdk-python
```

```python
import os
import asyncio
from openilink import OpeniLinkClient

async def main():
    client = OpeniLinkClient(
        hub_url="http://localhost:9800",
        token=os.environ["OPENILINK_TOKEN"],
    )

    @client.on_message
    async def handle(msg):
        print(f"[{msg.bot_id}] {msg.sender}: {msg.content}")
        await client.send_text(
            bot_id=msg.bot_id,
            to_user_id=msg.sender,
            content=f"你好,我收到了: {msg.content}",
        )

    await client.connect()

asyncio.run(main())
```

## Webhook Configuration

Configure a Webhook endpoint in the Hub dashboard under **Settings → Webhooks**. Hub will POST events to your URL:

```json
{
  "event": "message.received",
  "bot_id": "bot_abc123",
  "message": {
    "id": "msg_xyz",
    "sender": "user_openid",
    "content": "Hello",
    "type": "text",
    "timestamp": 1711900800
  }
}
```

### Express.js webhook handler
```javascript
import express from 'express';
import crypto from 'crypto';

const app = express();
app.use(express.json());

app.post('/webhook', (req, res) => {
  // Verify Hub signature
  const sig = req.headers['x-openilink-signature'];
  const expected = crypto
    .createHmac('sha256', process.env.WEBHOOK_SECRET)
    .update(JSON.stringify(req.body))
    .digest('hex');

  if (sig !== `sha256=${expected}`) {
    return res.status(401).json({ error: 'Invalid signature' });
  }

  const { event, bot_id, message } = req.body;

  if (event === 'message.received') {
    console.log(`Bot ${bot_id} received: ${message.content}`);
    // process message...
  }

  res.json({ ok: true });
});

app.listen(8080);
```

### Go webhook handler
```go
package main

import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/hex"
    "encoding/json"
    "fmt"
    "net/http"
    "os"
)

type WebhookEvent struct {
    Event   string  `json:"event"`
    BotID   string  `json:"bot_id"`
    Message Message `json:"message"`
}

type Message struct {
    ID        string `json:"id"`
    Sender    string `json:"sender"`
    Content   string `json:"content"`
    Type      string `json:"type"`
    Timestamp int64  `json:"timestamp"`
}

func webhookHandler(w http.ResponseWriter, r *http.Request) {
    var body []byte
    body, _ = io.ReadAll(r.Body)

    // Verify signature
    sig := r.Header.Get("X-OpeniLink-Signature")
    mac := hmac.New(sha256.New, []byte(os.Getenv("WEBHOOK_SECRET")))
    mac.Write(body)
    expected := "sha256=" + hex.EncodeToString(mac.Sum(nil))
    if sig != expected {
        http.Error(w, "Unauthorized", http.StatusUnauthorized)
        return
    }

    var event WebhookEvent
    if err := json.Unmarshal(body, &event); err != nil {
        http.Error(w, "Bad Request", http.StatusBadRequest)
        return
    }

    if event.Event == "message.received" {
        fmt.Printf("Bot %s received from %s: %s\n",
            event.BotID, event.Message.Sender, event.Message.Content)
    }

    w.Header().Set("Content-Type", "application/json")
    w.Write([]byte(`{"ok":true}`))
}

func main() {
    http.HandleFunc("/webhook", webhookHandler)
    http.ListenAndServe(":8080", nil)
}
```

## Building a Custom App

Apps integrate with Hub via WebSocket or Webhook and are authorized via PKCE OAuth.

### Minimal Go App (based on openilink-app-echo)
```bash
git clone https://github.com/openilink/openilink-app-echo.git my-app
cd my-app
```

```go
// main.go
package main

import (
    "context"
    "log"
    "os"

    app "github.com/openilink/openilink-app-sdk-go"
)

func main() {
    a := app.New(app.Config{
        AppID:     os.Getenv("APP_ID"),
        AppSecret: os.Getenv("APP_SECRET"),
        HubURL:    os.Getenv("HUB_URL"),
    })

    // Declare a command: users type /ping in WeChat
    a.RegisterCommand("ping", "Reply with pong", func(ctx context.Context, req *app.CommandRequest) error {
        return req.Reply("pong 🏓")
    })

    // Handle all messages
    a.OnMessage(func(ctx context.Context, msg *app.Message) error {
        log.Printf("Received: %s", msg.Content)
        return nil
    })

    if err := a.Start(context.Background()); err != nil {
        log.Fatal(err)
    }
}
```

**App manifest** (`app.json`) required for marketplace listing:
```json
{
  "id": "my-awesome-app",
  "name": "My Awesome App",
  "version": "1.0.0",
  "description": "Does something great with WeChat messages",
  "webhook_url": "https://my-app.example.com/webhook",
  "commands": [
    {
      "name": "ping",
      "description": "Replies with pong"
    }
  ],
  "scopes": ["messages:read", "messages:write"]
}
```

### Local Development with Mock Server
```bash
# Terminal 1: Start Mock Server (no real WeChat needed)
go run ./cmd/appmock --webhook-url http://localhost:8080/webhook

# Terminal 2: Run your App
APP_ID=test APP_SECRET=test HUB_URL=http://localhost:9801 go run .

# Terminal 3: Inject a test message
curl -X POST http://localhost:9801/mock/event \
  -H "Content-Type: application/json" \
  -d '{"sender":"alice","content":"/ping"}'

# Check what your App sent back
curl http://localhost:9801/mock/messages
```

## AI Auto-Reply Configuration

In the Hub dashboard → **Settings → AI**:

```env
# Set via env or dashboard
OPENAI_API_KEY=...        # Set in environment
OPENAI_BASE_URL=...       # For compatible APIs (Ollama, DeepSeek, etc.)
OPENAI_MODEL=gpt-4o-mini
AI_SYSTEM_PROMPT="You are a helpful WeChat assistant."
```

Compatible with any OpenAI-spec API (Ollama, DeepSeek, Qwen, etc.).

## REST API Patterns

Hub exposes a REST API at `http://localhost:9800/api/v1`.

```bash
# List connected bots
curl -H "Authorization: Bearer $OPENILINK_TOKEN" \
  http://localhost:9800/api/v1/bots

# Send a text message
curl -X POST \
  -H "Authorization: Bearer $OPENILINK_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"bot_id":"bot_abc","to_user_id":"user_openid","content":"Hello!"}' \
  http://localhost:9800/api/v1/messages/send

# Send an image
curl -X POST \
  -H "Authorization: Bearer $OPENILINK_TOKEN" \
  -F "bot_id=bot_abc" \
  -F "to_user_id=user_openid" \
  -F "image=@/path/to/image.png" \
  http://localhost:9800/api/v1/messages/send-image

# Get message trace (debugging)
curl -H "Authorization: Bearer $OPENILINK_TOKEN" \
  http://localhost:9800/api/v1/messages/trace/msg_xyz
```

## Common Patterns

### Pattern: Forward WeChat messages to Slack
Install the **Bridge** app from the marketplace, configure:
```env
BRIDGE_TARGET=slack
SLACK_WEBHOOK_URL=https://hooks.slack.com/services/...
BRIDGE_BOT_ID=bot_abc123   # which bot to bridge
```

### Pattern: Multi-bot message routing
```go
client.OnMessage(context.Background(), func(msg *openilink.Message) error {
    switch msg.BotID {
    case "bot_customer_service":
        return handleCustomerService(msg)
    case "bot_sales":
        return handleSales(msg)
    default:
        return handleDefault(msg)
    }
})
```

### Pattern: Command parsing in webhook
```python
@client.on_message
async def handle(msg):
    if msg.content.startswith("/"):
        parts = msg.content.split(maxsplit=1)
        cmd = parts[0][1:]   # strip leading /
        args = parts[1] if len(parts) > 1 else ""

        if cmd == "help":
            await client.send_text(
                bot_id=msg.bot_id,
                to_user_id=msg.sender,
                content="Commands: /help /status /ping"
            )
        elif cmd == "ping":
            await client.send_text(
                bot_id=msg.bot_id,
                to_user_id=msg.sender,
                content="pong!"
            )
```

## Troubleshooting

### Bot shows offline / session expired
- Hub auto-renews 24-hour iLink sessions. If a bot goes offline, check **Dashboard → Bots → Status**.
- Re-scan QR code from the bot detail page.
- Check logs: `journalctl -u openilink-hub -f` (if installed as service).

### Messages not delivered to Webhook
- Check **Dashboard → Messages → Trace** for the message — shows each delivery step with latency.
- Verify webhook URL is reachable from Hub (especially in Docker: use `host.docker.internal` not `localhost`).
- Confirm `WEBHOOK_SECRET` matches on both sides.

### Passkey login not working
- `RP_ORIGIN` must exactly match the browser URL (including port), e.g. `https://hub.example.com`.
- `RP_ID` must be the domain only, e.g. `hub.example.com`.
- Passkey requires HTTPS in production (localhost is exempt).

### App OAuth flow fails
- Ensure App's redirect URI is registered in Hub dashboard under **Apps → OAuth Settings**.
- PKCE is required — `code_challenge_method` must be `S256`.

### Docker networking: App can't reach Hub
```yaml
# Use service name, not localhost
environment:
  HUB_URL: http://hub:9800
```

### Database migration issues (PostgreSQL)
```bash
# Hub runs migrations automatically on start.
# To reset (destructive!):
docker compose down -v
docker compose up -d
```

## Project Structure (for contributors)

```
openilink-hub/
├── cmd/
│   ├── main.go          # CLI entrypoint (oih)
│   └── appmock/         # Mock server for App development
├── internal/
│   ├── api/             # REST API handlers
│   ├── broker/          # Message dispatch (App/WS/Webhook/AI)
│   ├── provider/        # iLink protocol adapter
│   └── store/           # SQLite/PostgreSQL data layer
├── web/                 # React 19 frontend
├── docs/
│   └── mock-server.md   # Mock server documentation
└── docker-compose.yml
```

## Related Repositories

| Repo | Purpose |
|------|---------|
| [openilink-sdk-go](https://github.com/openilink/openilink-sdk-go) | Go SDK |
| [openilink-sdk-node](https://github.com/openilink/openilink-sdk-node) | Node.js SDK |
| [openilink-sdk-python](https://github.com/openilink/openilink-sdk-python) | Python SDK |
| [openilink-app-echo](https://github.com/openilink/openilink-app-echo) | App development template |
| [openilink-app-command-service](https://github.com/openilink/openilink-app-command-service) | 20+ built-in commands |
| [openclaw-channels](https://github.com/openilink/openclaw-channels) | OpenClaw AI Agent integration |
```

Attribution

reason-machinesreason-machines
View sourceMore from reason-machines →
SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Related Skills

Browser Extension Developer

Use this skill when developing or maintaining browser extension code in the `browser/` directory, including Chrome/Firefox/Edge compatibility, content scripts, background scripts, or i18n updates.

281612 votes

Seo Optimizer

SEO optimization with keyword analysis, readability assessment, technical validation, content quality. Use for search rankings, blog posts, content audits, or encountering keyword density, readability scores, meta tags, schema markup errors.

2132 votes

Google Official Seo Guide

Official Google SEO guide covering search optimization, best practices, Search Console, crawling, indexing, and improving website search visibility based on official Google documentation

1862 votes

Tanstack Start

Build a full-stack TanStack Start app on Cloudflare Workers from scratch — SSR, file-based routing, server functions, D1+Drizzle, better-auth, Tailwind v4+shadcn/ui. Use whenever the user mentions TanStack Start, asks to scaffold a full-stack Cloudflare app with SSR, wants an SSR dashboard, or asks for a React 19 + Cloudflare Workers app with file-based routing and server functions — even if they don't name TanStack Start specifically. No template repo — Claude generates every file fresh per ...

9881 votes

Pentest

PTES-aligned adversarial security audit for backend, frontend, and mobile applications. Produces a CVSS-scored Hacker Report with verified PoCs and phased remediation.

5491 votes
View all in development →