skills/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
tools
Plans real-user QA deliverables: personas, journey maps, exploratory charters, persona/journey/tour/CFR test cases, regression suites, Figma validation checks, automation intent, and user-impact bug reports. Writes artifacts under <qa-output-path>/qa/ for qa-execution to consume. Use when planning QA before execution, documenting journey-driven test strategy, marking flows that need E2E follow-up, or filing structured bug reports. Do not use for live execution, AI implementation audits, CI gate ownership, or technical integration/security/performance suites; use qa-execution or agent-output-audit instead.
development
Executes real-user QA sessions through public interfaces using personas, journeys, exploratory charters, test tours, edge-case probes, CFR checks, and browser evidence. Reads qa-report artifacts from <qa-output-path>/qa/ when present, captures issues/screenshots/reports under the same output tree, and classifies bugs by user impact. Use when validating a release candidate, migration, refactor, or user-facing change against production-like behavior. Do not use for AI implementation audits, task-status reconciliation, CI gate runs, integration/security/performance templates, or flaky-test triage; use agent-output-audit for those.
development
Transform outside-of-diff review files into properly formatted issue files for a given PR. Use when converting review files from ai-docs/reviews-pr-<PR>/outside/ into issue format in ai-docs/reviews-pr-<PR>/issues/. Automatically determines starting issue number and preserves all metadata (file path, date, status) from original review files. Don't use for inline-diff review files, non-PR review artifacts, or creating GitHub issues directly.
development
Enforce root-cause fixes over workarounds, hacks, and symptom patches in all software engineering tasks. Use when debugging issues, fixing bugs, resolving test failures, planning solutions, making architectural decisions, or reviewing code changes. Activates gate functions that detect and reject common workaround patterns such as type assertions, lint suppressions, error swallowing, timing hacks, and monkey patches. Don't use for trivial formatting changes or documentation-only edits.