Claude Skills Guide

Claude Skills for WebSocket Realtime App Development

Real-time communication has become essential for modern web applications Chat systems, live dashboards, collaborative tools, and gaming platforms all rely on WebSocket connections to deliver instant data updates. Building these features from scratch presents unique challenges that Claude skills can help you overcome.

This guide shows you how to use specific Claude skills to accelerate WebSocket development, from initial architecture to production deployment.

Why WebSocket Development Benefits from Claude Skills

WebSocket development differs significantly from traditional HTTP request-response patterns. You must handle connection lifecycles, manage bidirectional messaging, implement reconnection logic, and deal with state synchronization across client and server. These concerns create boilerplate that takes time to implement correctly.

Claude skills encapsulate best practices for these patterns. Rather than researching solutions each time, you invoke a skill that applies proven approaches to your specific codebase. The skills work alongside your existing stack—whether you use Node.js, Python, or Go on the backend, and React, Vue, or vanilla JavaScript on the frontend.

Essential Skills for WebSocket Projects

Several Claude skills prove particularly valuable when building real-time applications. Each addresses a specific aspect of the development workflow.

frontend-design for UI Components

The frontend-design skill helps you create the visual layer of your real-time application. When building WebSocket-powered interfaces, you need components that handle incoming data gracefully—status indicators, message lists, live counters, and notification systems.

With frontend-design, you describe your requirements and receive implementation code that follows modern patterns:

Create a message thread component that displays real-time updates with fade-in animations and a connection status badge in the corner.

The skill generates React or Vue components with proper state management for handling WebSocket messages. It ensures your UI updates efficiently without unnecessary re-renders, which matters significantly when handling high-frequency updates.

tdd for Protocol Implementation

Writing tests for WebSocket code requires understanding connection states, message formats, and timing considerations. The tdd skill guides you through test-driven development for real-time systems.

When you invoke tdd, it helps you:

The skill suggests test patterns specific to your testing framework. For instance, if you use Jest, it might recommend using fake timers and connection mocks to create deterministic tests for reconnection logic.

pdf for Documentation

Production WebSocket applications need documentation—API specifications, protocol guides, and architecture decisions. The pdf skill enables you to generate documentation from your codebase.

When your WebSocket protocol evolves, use pdf to export updated documentation:

Generate a PDF documenting the WebSocket message format, including the JSON schema for each message type and example payloads.

This keeps your team aligned without maintaining separate documentation files.

Practical Implementation Patterns

Let me walk through how these skills work together in a real project scenario.

Setting Up the Connection Layer

Before writing your connection manager, initialize your project with the necessary dependencies:

mkdir websocket-server && cd websocket-server
npm init -y
npm install ws express

Create your main server file with Express and the ws library:

const WebSocket = require('ws');
const express = require('express');
const http = require('http');

const app = express();
const server = http.createServer(app);
const wss = new WebSocket.Server({ server });

wss.on('connection', (ws, req) => {
  console.log('Client connected');

  ws.on('message', (message) => {
    const data = JSON.parse(message);
    handleMessage(ws, data);
  });

  ws.on('close', () => {
    console.log('Client disconnected');
  });
});

function handleMessage(ws, data) {
  switch (data.type) {
    case 'ping':
      ws.send(JSON.stringify({ type: 'pong', timestamp: Date.now() }));
      break;
    case 'broadcast':
      wss.clients.forEach(client => {
        if (client.readyState === WebSocket.OPEN) {
          client.send(JSON.stringify(data.payload));
        }
      });
      break;
  }
}

server.listen(8080, () => {
  console.log('WebSocket server running on port 8080');
});

Once your scaffold is in place, build a more complete connection manager. Use the tdd skill to drive the implementation:

class WebSocketManager {
  constructor(url, options = {}) {
    this.url = url;
    this.options = options;
    this.socket = null;
    this.reconnectAttempts = 0;
    this.maxReconnectAttempts = options.maxReconnectAttempts || 5;
    this.listeners = new Map();
  }

  connect() {
    this.socket = new WebSocket(this.url);

    this.socket.onopen = () => {
      this.reconnectAttempts = 0;
      this.emit('connected');
    };

    this.socket.onclose = (event) => {
      this.handleReconnect();
    };

    this.socket.onmessage = (event) => {
      const data = JSON.parse(event.data);
      this.emit(data.type, data.payload);
    };
  }

  handleReconnect() {
    if (this.reconnectAttempts < this.maxReconnectAttempts) {
      this.reconnectAttempts++;
      setTimeout(() => this.connect(), this.getBackoffDelay());
    }
  }

  getBackoffDelay() {
    return Math.min(1000 * Math.pow(2, this.reconnectAttempts), 30000);
  }
}

The tdd skill would have guided you to write tests covering connection success, connection failure, message routing, and exponential backoff before writing this implementation.

Message Protocol Design

Establish a consistent message protocol across your application. The following schema captures the minimal contract your client and server should share:

// Message schema
const messageSchema = {
  type: 'string',      // Required: event type
  payload: 'object',   // Required: event data
  id: 'string',        // Optional: message ID for acknowledgment
  timestamp: 'number'  // Optional: client timestamp
};

Including an optional id field allows you to implement request-acknowledgment patterns where the server echoes the id back to confirm receipt. The timestamp field helps measure latency and order out-of-sequence messages on the client.

React Hook for WebSocket State

The custom hook pattern keeps your WebSocket logic reusable across components. Use the frontend-design skill to scaffold this:

// useWebSocket.js
import { useState, useEffect, useCallback, useRef } from 'react';

export function useWebSocket(url) {
  const [messages, setMessages] = useState([]);
  const [connected, setConnected] = useState(false);
  const wsRef = useRef(null);

  const connect = useCallback(() => {
    wsRef.current = new WebSocket(url);

    wsRef.current.onopen = () => {
      setConnected(true);
    };

    wsRef.current.onmessage = (event) => {
      const message = JSON.parse(event.data);
      setMessages((prev) => [...prev, message]);
    };

    wsRef.current.onclose = () => {
      setConnected(false);
      // Attempt reconnection after 3 seconds
      setTimeout(connect, 3000);
    };

    wsRef.current.onerror = (error) => {
      console.error('WebSocket error:', error);
    };
  }, [url]);

  const sendMessage = useCallback((message) => {
    if (wsRef.current?.readyState === WebSocket.OPEN) {
      wsRef.current.send(JSON.stringify(message));
    }
  }, []);

  useEffect(() => {
    connect();
    return () => {
      wsRef.current?.close();
    };
  }, [connect]);

  return { messages, connected, sendMessage };
}

This hook handles connection lifecycle, automatic reconnection, and message state—patterns you’ll reuse across real-time features.

Building Real-Time UI Components

Once your connection layer exists, use frontend-design to create components that consume it. A chat interface might look like:

function ChatComponent({ wsManager }) {
  const [messages, setMessages] = useState([]);
  const [status, setStatus] = useState('disconnected');

  useEffect(() => {
    wsManager.on('connected', () => setStatus('connected'));
    wsManager.on('message', (payload) => {
      setMessages(prev => [...prev, payload]);
    });
  }, [wsManager]);

  return (
    <div className="chat-container">
      <div className="status-badge">{status}</div>
      <MessageList messages={messages} />
    </div>
  );
}

The frontend-design skill ensures your components follow your project’s styling conventions and include accessibility considerations.

Generating Protocol Documentation

As your application grows, document your message protocol. Use pdf to create a reference document:

## WebSocket Protocol Specification

### Message Format
All messages use JSON with the following structure:

{
  "type": "string",
  "payload": "object",
  "timestamp": "ISO8601"
}

### Message Types

#### chat.message
- payload: { userId, content, roomId }
- Direction: Client to Server

#### chat.broadcast
- payload: { messageId, userId, content, timestamp }
- Direction: Server to Client

The pdf skill converts this markdown into a formatted PDF your team can reference.

Heartbeat Detection for Stale Connections

Production WebSocket servers must detect and close stale connections. Implement ping/pong heartbeats on the server:

// server.js
const { WebSocketServer } = require('ws');

const wss = new WebSocketServer({ port: 8080 });

wss.on('connection', (ws) => {
  ws.isAlive = true;

  ws.on('pong', () => {
    ws.isAlive = true;
  });

  // Send ping every 30 seconds
  const interval = setInterval(() => {
    if (ws.isAlive === false) {
      clearInterval(interval);
      return ws.terminate();
    }
    ws.isAlive = false;
    ws.ping();
  }, 30000);

  ws.on('close', () => {
    clearInterval(interval);
  });
});

To keep the heartbeat logic reusable, extract it into a named function you can apply to every new connection:

const HEARTBEAT_INTERVAL = 30000;

function setupHeartbeat(ws) {
  ws.isAlive = true;

  ws.on('pong', () => {
    ws.isAlive = true;
  });

  const interval = setInterval(() => {
    if (ws.isAlive === false) {
      clearInterval(interval);
      return ws.terminate();
    }

    ws.isAlive = false;
    ws.ping();
  }, HEARTBEAT_INTERVAL);

  ws.on('close', () => clearInterval(interval));
}

wss.on('connection', (ws) => {
  setupHeartbeat(ws);
  // ...rest of connection logic
});

Pair this with a client-side connection status indicator:

function ConnectionStatus({ connected }) {
  const statusStyles = {
    connected: 'bg-green-500',
    disconnected: 'bg-red-500'
  };

  return (
    <div className={`w-3 h-3 rounded-full ${statusStyles[connected ? 'connected' : 'disconnected']}`} />
  );
}

Python Asyncio WebSocket Server

If your backend stack is Python, Claude skills work equally well for asyncio-based implementations. Here is a subscription-based event server:

# websocket-server.py
import asyncio
import websockets
import json
from datetime import datetime

async def handle_client(websocket, path):
    try:
        async for message in websocket:
            data = json.loads(message)

            if data.get('type') == 'subscribe':
                channel = data.get('channel')
                await websocket.send(json.dumps({
                    'type': 'subscribed',
                    'channel': channel,
                    'timestamp': datetime.now().isoformat()
                }))

            elif data.get('type') == 'event':
                event_type = data.get('event_type')
                payload = data.get('payload')
                print(f"Received event: {event_type}")
                await broadcast_event(event_type, payload)

    except websockets.exceptions.ConnectionClosed:
        print("Client disconnected")

async def broadcast_event(event_type, payload):
    # Broadcast to all connected subscribers
    pass

async def main():
    async with websockets.serve(handle_client, "localhost", 8765):
        print("WebSocket server running on ws://localhost:8765")
        await asyncio.Future()  # Run forever

if __name__ == "__main__":
    asyncio.run(main())

For Python clients with robust reconnection, use an exponential backoff class:

import websocket
import time
import json

class ReconnectingClient:
    def __init__(self, url, max_retries=5):
        self.url = url
        self.max_retries = max_retries
        self.ws = None

    def connect(self):
        retries = 0
        while retries < self.max_retries:
            try:
                self.ws = websocket.WebSocketApp(
                    self.url,
                    on_message=self.on_message,
                    on_error=self.on_error,
                    on_close=self.on_close
                )
                self.ws.on_open = self.on_open
                self.ws.run_forever()
            except Exception as e:
                retries += 1
                wait_time = min(2 ** retries, 30)
                print(f"Reconnecting in {wait_time}s (attempt {retries})")
                time.sleep(wait_time)

        print("Max retries exceeded")

    def on_message(self, ws, message):
        data = json.loads(message)
        # Process message

    def on_open(self, ws):
        ws.send(json.dumps({'type': 'subscribe', 'channel': 'events'}))

    def on_error(self, ws, error):
        print(f"Error: {error}")

    def on_close(self, ws, close_status_code, close_msg):
        print("Connection closed, attempting reconnect...")

Live Dashboard Pattern

For skills that drive visual dashboards, Claude skills can generate a bridge between your WebSocket stream and a file-polled frontend:

# dashboard-updater.py
import websocket
import json

def on_message(ws, message):
    data = json.loads(message)

    if data['type'] == 'update':
        with open('./public/live-data.json', 'w') as f:
            json.dump(data['payload'], f)
        print(f"Updated dashboard at {data['timestamp']}")

def on_open(ws):
    ws.send(json.dumps({
        'type': 'subscribe',
        'channel': 'metrics'
    }))

if __name__ == "__main__":
    ws = websocket.WebSocketApp(
        "ws://localhost:8765",
        on_open=on_open,
        on_message=on_message,
        on_error=lambda ws, e: print(f"Error: {e}"),
        on_close=lambda ws, c, m: print("Connection closed")
    )
    ws.run_forever()

The frontend-design skill can then generate a dashboard that polls this file for updates, creating a near-real-time experience without a persistent browser WebSocket connection.

Advanced Considerations

Handling High-Frequency Updates

When your application sends many messages per second, consider implementing:

The tdd skill helps you test these optimizations without introducing bugs.

Scaling WebSocket Connections with Redis

At scale, a single server cannot maintain all connections. Redis pub/sub enables cross-server message broadcasting:

const Redis = require('ioredis');
const redis = new Redis();

const wss = new WebSocketServer({ port: 8080 });

// Subscribe to Redis channel
redis.subscribe('chat-messages', (err) => {
  if (err) console.error('Redis subscribe error:', err);
});

redis.on('message', (channel, message) => {
  // Broadcast Redis messages to all connected WebSocket clients
  wss.clients.forEach((client) => {
    if (client.readyState === WebSocket.OPEN) {
      client.send(message);
    }
  });
});

wss.on('connection', (ws) => {
  ws.on('message', (message) => {
    // Publish to Redis for other servers to receive
    redis.publish('chat-messages', message);
  });
});

This pattern ensures messages reach all connected clients regardless of which server instance handles the original request. Pair it with:

Document your architecture using pdf so operations teams can maintain the system.

Security Best Practices

Always implement:

The tdd skill can guide you to write security tests covering these concerns. A basic token-based authentication pattern that validates the token and places the user into a personal channel:

wss.on('connection', (ws, req) => {
  const url = new URL(req.url, `http://${req.headers.host}`);
  const token = url.searchParams.get('token');

  if (!validateToken(token)) {
    ws.close(4001, 'Authentication failed');
    return;
  }

  const userId = getUserIdFromToken(token);
  ws.userId = userId;

  // Join user to their personal channel
  joinRoom(ws, `user:${userId}`);
});

For more granular channel authorization, extend this pattern to verify access on each incoming message:

wss.on('connection', (ws, req) => {
  const url = new URL(req.url, `http://${req.headers.host}`);
  const token = url.searchParams.get('token');

  try {
    const user = verifyToken(token);
    ws.user = user;
  } catch (error) {
    ws.close(4001, 'Authentication required');
    return;
  }

  ws.on('message', (message) => {
    const data = JSON.parse(message);
    if (!canUserAccessChannel(ws.user, data.channel)) {
      ws.send(JSON.stringify({ error: 'Access denied' }));
      return;
    }
    // Process message...
  });
});

Testing WebSocket Applications

Write integration tests that verify message flow end-to-end. The tdd skill helps you structure these:

// tests/websocket.test.js
const { WebSocket } = require('ws');

describe('WebSocket Chat', () => {
  let server;

  beforeAll(() => {
    server = require('../server');
  });

  afterAll(() => {
    server.close();
  });

  it('broadcasts messages to all clients', (done) => {
    const client1 = new WebSocket('ws://localhost:8080');
    const client2 = new WebSocket('ws://localhost:8080');

    client1.on('open', () => {
      client2.on('open', () => {
        client1.send(JSON.stringify({ text: 'Hello' }));
      });

      client2.on('message', (data) => {
        const message = JSON.parse(data);
        expect(message.text).toBe('Hello');
        client1.close();
        client2.close();
        done();
      });
    });
  });
});

The supermemory skill benefits from WebSocket connections when syncing memories across devices in real-time. The tdd skill can stream test results as they execute, providing immediate feedback. For documentation generation with the docx skill, WebSocket connections enable progress updates during lengthy document assembly.

Debugging and Monitoring

Intermittent connection drops and race conditions are among the hardest WebSocket bugs to reproduce. The superMemory skill maintains your investigation context across multiple Claude sessions, so you can continue a debugging thread without re-explaining the problem from scratch.

Implement structured logging to capture connection metrics:

function logConnectionEvent(event) {
  console.log(JSON.stringify({
    timestamp: Date.now(),
    event: event.type,
    clientId: event.clientId,
    serverTime: Date.now()
  }));
}

Call logConnectionEvent on connection, disconnection, authentication failures, and message errors. Structured JSON output lets you pipe logs into aggregation tools (Datadog, Loki, CloudWatch) for alerting and trend analysis without additional parsing.

The docx skill is also useful here: it creates formatted Word documents for post-incident reports and architectural decision records that require tracked changes or collaborative editing.

Bringing It Together

Building WebSocket real-time applications requires coordination across multiple concerns—connection management, UI updates, documentation, and testing. Claude skills provide structured guidance for each aspect.

Start with tdd to establish your connection layer with proper test coverage. Use frontend-design for the reactive components that display real-time data. Keep your protocol documented with pdf as it evolves. These skills work together to accelerate your development cycle while maintaining code quality.

The combination of test-driven development, thoughtful UI implementation, and living documentation creates a foundation you can build on—whether you’re building a simple chat or a complex collaborative platform.


Built by theluckystrike — More at zovo.one