skills/community/centrifugo/SKILL.md
Centrifugo real-time messaging server expert for WebSocket PUB/SUB, channel management, JWT authentication, event proxying, and horizontal scaling with Redis/NATS. Use when: centrifugo, centrifugal, real-time messaging, websocket pubsub, channel subscriptions, real-time notifications, live updates, presence, history recovery, server-sent events integration, real-time transport layer. Do not use for: general WebSocket programming without Centrifugo, Socket.IO, Pusher SDK, or other real-time frameworks.
npx skillsauth add pedronauck/skills centrifugoInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Centrifugo is a self-hosted, language-agnostic real-time messaging server. It handles persistent connections (WebSocket, SSE, HTTP-streaming, WebTransport, GRPC) and broadcasts messages via a channel-based PUB/SUB model. The application backend publishes to channels via Server API; Centrifugo delivers to online subscribers instantly.
Backend App ──(HTTP/GRPC Server API)──> Centrifugo Cluster ──(WebSocket/SSE)──> Clients
│
Redis/NATS Broker
(for multi-node)
Key principle: All user-generated data flows through the application backend first (validate, persist, then publish to Centrifugo). Centrifugo is the transport layer, not the source of truth.
Identify the real-time feature being built and select the appropriate pattern:
Generate a minimal configuration:
centrifugo genconfig # Creates config.json
Or use Docker:
docker run -p 8000:8000 centrifugo/centrifugo:v6 centrifugo
Essential configuration structure (JSON, YAML, or TOML supported):
{
"client": {
"token": {
"hmac_secret_key": "<SECRET>"
},
"allowed_origins": ["http://localhost:3000"]
},
"http_api": {
"key": "<API_KEY>"
},
"channel": {
"without_namespace": {
"allow_subscribe_for_client": true
}
}
}
Read references/configuration.md for the full configuration reference including TLS, admin UI, environment variables, and advanced options.
Centrifugo authenticates clients via JWT or connect proxy.
JWT approach (recommended for most cases):
sub (user ID) and exp claims, signed with the configured HMAC/RSA/ECDSA key.# Backend: generate connection JWT (Python example)
import jwt, time
token = jwt.encode(
{"sub": "user123", "exp": int(time.time()) + 3600},
"<HMAC_SECRET>", algorithm="HS256"
)
// Client: connect with token
const client = new Centrifuge("ws://localhost:8000/connection/websocket", {
token: "<JWT_TOKEN>",
});
client.connect();
Connect proxy approach (alternative):
Read references/authentication.md for JWT claims, token refresh, proxy auth, and channel-level authorization tokens.
Channels are ephemeral strings that serve as message pathways. Use namespaces to apply different behaviors.
Naming conventions:
chat:room-123 — namespace chat, channel for room 123notifications:user#42 — user-limited channel (only user 42 can subscribe)$private:secret — private channel prefix (requires subscription token)Namespace configuration:
{
"channel": {
"namespaces": [
{
"name": "chat",
"presence": true,
"history_size": 50,
"history_ttl": "300s",
"force_recovery": true,
"join_leave": true
},
{
"name": "notifications",
"allow_user_limited_channels": true
}
]
}
}
Read references/channels.md for all channel options, namespace rules, and special channel prefixes.
Use HTTP or GRPC to publish messages from the application backend.
HTTP API — POST to /api/<method> with X-API-Key header:
# Publish to a channel
curl -X POST -H "X-API-Key: <KEY>" -H "Content-Type: application/json" \
-d '{"channel": "chat:room-1", "data": {"text": "hello"}}' \
http://localhost:8000/api/publish
# Broadcast to multiple channels
curl -X POST -H "X-API-Key: <KEY>" -H "Content-Type: application/json" \
-d '{"channels": ["user:1", "user:2"], "data": {"text": "hello"}}' \
http://localhost:8000/api/broadcast
Available API methods: publish, broadcast, subscribe, unsubscribe, disconnect, refresh, presence, presence_stats, history, history_remove, channels, info, batch.
Read references/server-api.md for all method signatures, request/response schemas, and HTTP API library links.
Official SDKs: centrifuge-js (browser/Node/React Native), centrifuge-go, centrifuge-dart (Flutter), centrifuge-swift (iOS), centrifuge-java (Android), centrifuge-python.
JavaScript client pattern:
import { Centrifuge } from "centrifuge";
const client = new Centrifuge("ws://localhost:8000/connection/websocket", {
token: "<JWT>",
});
// Connection state handlers
client.on("connecting", ctx => console.log("connecting", ctx));
client.on("connected", ctx => console.log("connected", ctx));
client.on("disconnected", ctx => console.log("disconnected", ctx));
// Subscribe to channel
const sub = client.newSubscription("chat:room-1");
sub.on("publication", ctx => {
console.log("received:", ctx.data);
});
sub.on("subscribing", ctx => console.log("subscribing", ctx));
sub.on("subscribed", ctx => console.log("subscribed", ctx));
sub.subscribe();
client.connect();
Client states: disconnected -> connecting -> connected (auto-reconnect with exponential backoff).
Subscription states: unsubscribed -> subscribing -> subscribed (auto-resubscribe on reconnect).
Read references/client-sdk.md for all SDK patterns, token refresh, presence/history from client, RPC calls, and Protobuf mode.
Proxy client events to the backend for validation and custom logic.
Supported proxy events:
connect — authenticate connections without JWTrefresh — extend client sessionssubscribe — validate channel accesspublish — validate publications from clientsrpc — handle custom client-to-server callssub_refresh — extend subscription sessions{
"client": {
"proxy": {
"connect": {
"enabled": true,
"endpoint": "http://backend:3000/centrifugo/connect"
},
"rpc": {
"enabled": true,
"endpoint": "http://backend:3000/centrifugo/rpc"
}
}
},
"channel": {
"namespaces": [
{
"name": "chat",
"proxy": {
"subscribe": {
"enabled": true,
"endpoint": "http://backend:3000/centrifugo/subscribe"
},
"publish": {
"enabled": true,
"endpoint": "http://backend:3000/centrifugo/publish"
}
}
}
]
}
}
Read references/proxy.md for proxy request/response schemas, GRPC proxy, header forwarding, and timeout configuration.
Memory engine (default): Single node only. Fast, no dependencies. Suitable for development and small deployments.
Redis engine: Multi-node clusters. Messages published on any node reach all subscribers.
{
"engine": {
"type": "redis",
"redis": {
"address": "redis://localhost:6379"
}
}
}
Supports Redis Sentinel, Redis Cluster, consistent sharding across multiple Redis instances, and Redis-compatible storages (Valkey, DragonflyDB, KeyDB, AWS ElastiCache).
NATS broker: Alternative for PUB/SUB only (no history/presence persistence).
Read references/engines.md for Redis Sentinel/Cluster setup, sharding, NATS configuration, and separate broker/presence manager configuration.
History allows caching recent publications per channel. Recovery automatically restores missed messages after reconnection.
{
"channel": {
"namespaces": [
{
"name": "chat",
"history_size": 100,
"history_ttl": "600s",
"force_recovery": true,
"force_positioning": true
}
]
}
}
history_size + history_ttl: Define retention window.force_recovery: Clients automatically recover missed messages on reconnect.force_positioning: Detect publication gaps.references/channels.md for details.Centrifugo exposes Prometheus metrics at /metrics and supports structured logging.
{
"log_level": "info",
"prometheus": {
"enabled": true
},
"health": {
"enabled": true
}
}
Metrics include: connections, subscriptions, publications, API calls, transport stats, and engine stats.
History is an ephemeral hot cache designed to reduce database load during reconnect storms. Always maintain a primary application database.
Design with graceful degradation. If Centrifugo goes down, the application should still function (just without real-time updates). Return data in API responses, not only via channels.
allowed_origins in productionEmpty allowed_origins blocks all browser connections. Configure it with the exact origins of the frontend application.
Always validate client publications through either:
Namespaces provide granular control over channel behavior and permissions. Define a namespace for each real-time feature.
Set reasonable exp claims in JWTs. Too short = excessive refresh requests. Too long = delayed user deactivation. Implement the token refresh callback in client SDKs.
102: unknown channel — verify the namespace is defined in configuration.103: permission denied — check channel permissions (allow_subscribe_for_client, subscription JWT, or subscribe proxy).allowed_origins, JWT validity/expiration, and network connectivity.redis://, rediss:// for TLS, redis+sentinel:// for Sentinel, redis+cluster:// for Cluster).Centrifugo integrates well with any backend language/framework. Common setups include:
centrifuge npm package for server-side operations.centrifuge Go library directly or the Centrifugo HTTP/GRPC API.pycent library or direct HTTP API calls.phpcent library.For the JavaScript client SDK (centrifuge-js), install via npm:
npm install centrifuge
# or
bun add centrifuge
development
Deep review of branch diffs, working trees, or GitHub PRs at any size. Use when the user asks for CodeRabbit-grade review, an incremental re-review after new pushes, publication of findings to a PR, a cross-LLM peer-review verdict round, or conformance review against spec artifacts. Don't use for applying fixes, reviewing specs or PRDs as documents, or quick single-file feedback.
tools
Orchestrate Claude and Codex worker TUIs from a controller agent through herdr panes and the herdr socket CLI. Use when delegating bounded tasks to herdr worker panes, running user-activated plan-first delegations (Claude Code plan mode, Codex Plan mode), waiting on native agent status (idle, working, blocked, done), or verifying worker reports. Workers launch as interactive TUIs via herdr agent start — never through headless runners (compozy exec, claude -p, codex exec). Not for cmux workspaces (see cmux-orchestration) and not for end-user herdr control.
tools
TanStack Query, Router, and Form patterns for React. Use when writing useQuery/queryOptions, mutations, caching, file-based routes, search params, loaders, or TanStack Form validation. Don't use for TanStack Start, TanStack DB/collections, Zustand client state, or non-TanStack routing.
development
Use when the user wants to design, redesign, shape, critique, audit, polish, clarify, distill, harden, optimize, adapt, animate, colorize, extract, or otherwise improve a frontend interface. Covers websites, landing pages, dashboards, product UI, app shells, components, forms, settings, onboarding, and empty states. Handles UX review, visual hierarchy, information architecture, cognitive load, accessibility, performance, responsive behavior, theming, anti-patterns, typography, fonts, spacing, layout, alignment, color, motion, micro-interactions, UX copy, error states, edge cases, i18n, and reusable design systems or tokens. Also use for bland designs that need to become bolder or more delightful, loud designs that should become quieter, live browser iteration on UI elements, or ambitious visual effects that should feel technically extraordinary. Not for backend-only or non-UI tasks.