Connection
WebSocket Endpoint
The server accepts the WebSocket connection immediately and adds the client to an internal broadcast hub.
Message Protocol
Client to Server
Clients can send any text message to keep the connection alive. The server does not process client messages but requires the connection to receive data to stay open. Keepalive Pattern:The server ignores message content from clients. Sending messages is only necessary to prevent connection timeouts.
Server to Client
The server sends JSON messages when markdown files are modified externally by other processes or editors.File Changed Event
Broadcast when a watched markdown file is modified, created, or moved. Message Type:file_changed
File Mode Fields:
string
required
Always
"file_changed"string
required
Updated markdown content of the file
string
required
Always
"file_changed"string
required
Relative path of the changed file
string
Updated markdown content (included if the file is readable)
Examples
File Mode
When running in single-file mode, the server watches one markdown file and broadcasts its content when changed. Server Message:Folder Mode
When running in folder mode, the server watches all markdown files in the directory tree and broadcasts changes with the file path. Server Message (with content):content is omitted:
Event Triggers
The server uses Watchdog to monitor file system events. Monitored Events:- File modified (content changed)
- File created (new markdown file)
- File moved (renamed or relocated)
File Mode: Only changes to the target file trigger notifications.Folder Mode: Only markdown files (
.md, .markdown) within the workspace trigger notifications.POST /api/save request to avoid echoing the client’s own saves.
Connection Lifecycle
Connection Established
- Client initiates WebSocket handshake to
/ws - Server accepts connection via
websocket.accept() - Server adds client to internal
WebSocketHub - Client is now subscribed to all file change broadcasts
Connection Maintenance
The server keeps the connection open by continuously awaiting messages:Connection Closed
Client-initiated close:- Client closes WebSocket connection
- Server receives
WebSocketDisconnectexception - Server removes client from
WebSocketHub
- Server detects stale connection during broadcast
- Server catches
RuntimeErrorwhen sending fails - Server removes client from
WebSocketHub
Broadcasting
The server uses a fan-out pattern to broadcast messages to all connected clients.Broadcast Flow
- File system event detected by Watchdog observer
- Callback scheduled on event loop via
loop.call_soon_threadsafe() - Validation checks if event should be ignored (self-write, wrong file, throttled)
- Content read from disk (skipped if read fails)
- JSON payload constructed with
type,file, andcontent - Broadcast to all clients in
WebSocketHub._clientsset - Stale clients removed if send fails with
RuntimeError
Concurrency
TheWebSocketHub uses an asyncio.Lock to protect the client set during:
- Adding new connections
- Removing disconnected clients
- Iterating for broadcasts
Error Handling
Client Errors
Connection refused:Server Errors
File read failure: If the server cannot read a changed file, it broadcasts the event withoutcontent:
GET /api/content.
Broadcast failure:
If sending to a client fails, the server silently removes that client and continues broadcasting to others.
Complete Example
React Hook
Python CLI Monitor
Technical Details
Implementation
- Framework: FastAPI WebSocket support
- File watcher: Watchdog library
- Concurrency:
asynciowith thread-safe event scheduling - Hub pattern: Single
WebSocketHubmanages all client connections
Performance
- Broadcast latency: Typically < 50ms from file system event to client delivery
- Scalability: Tested with 100+ concurrent WebSocket connections
- Memory: ~1KB per connected client
Limitations
See Also
- HTTP Endpoints - REST API reference
- Server API - Python API for creating the server
- FastAPI WebSocket Documentation