How the Server Edition of nodeterm Serves the Renderer to a Browser

The Server Edition of nodeterm delivers the React-based canvas UI to browsers through a lightweight HTTP server, WebSocket RPC layer, and platform shim that replaces Electron's IPC with web-native protocols while reusing the same core services.

The Server Edition of nodeterm provides a headless backend that renders the terminal's interface directly in any modern web browser instead of wrapping it in an Electron window. Located in the src/server/ directory of the eneskirca/nodeterm repository, this architecture abstracts the CorePlatform interface through an HTTP and WebSocket stack, eliminating Electron-specific dependencies while maintaining full compatibility with the desktop edition's file system, Git, and agent services. This implementation allows users to access the complete nodeterm experience through a standard browser without installing the desktop application.

Static HTTP Server for Compiled Assets

The Server Edition begins with a lightweight HTTP implementation in src/server/http.ts that creates an Express-style server. This server delivers the compiled front-end assets from the out/renderer/ directory—the output of the Vite build process—as static files.

When a browser navigates to the root endpoint, the server returns index.html, which loads the bundled JavaScript and CSS required to boot the React-based canvas. This approach ensures the browser receives the exact same renderer code that would normally execute inside an Electron window, maintaining visual and functional parity between the desktop and web editions.

WebSocket RPC Layer

While the HTTP server handles static assets, src/server/ws.ts establishes the real-time communication channel essential for terminal functionality. This module creates a WebSocket endpoint at /ws that replaces Electron's ipcMain/ipcRenderer communication model.

The browser connects to this endpoint through the window.nodeTerminal bridge located in src/renderer/bridge/. Once connected, the server instantiates an RpcRouter from src/shared/rpc.ts to handle the shared RPC protocol used by both desktop and server editions. This router multiplexes all IPC calls—including file-system operations, Git services, and agent-status updates—over the WebSocket connection, allowing the same core services to function in a pure browser environment.

// src/server/ws.ts
import { WebSocketServer } from 'ws';
import { RpcRouter } from '../shared/rpc';
import { ServerPlatform } from './platform-server';

export function createWsServer(http, platform: ServerPlatform) {
  const wss = new WebSocketServer({ server: http });

  wss.on('connection', (socket) => {
    const router = new RpcRouter(socket, platform);
    router.registerHandlers();   // registers all core RPC methods
  });
}

ServerPlatform Shim Implementation

The critical abstraction enabling browser compatibility resides in src/server/platform-server.ts. This file provides the ServerPlatform class, which implements the same CorePlatform interface used by the desktop application but isolates the renderer from any Electron API imports.

ServerPlatform fulfills the core contract by forwarding RPC calls to appropriate server-side handlers. For example, when the renderer invokes file-system operations, the shim translates these calls into method invocations that execute in the Node.js environment rather than the browser sandbox. This architectural boundary ensures the React components remain platform-agnostic, running identically whether loaded in Electron or served to a browser.

// src/server/main.ts
import { createHttpServer } from './http';
import { createWsServer } from './ws';
import { ServerPlatform } from './platform-server';

// Initialise the core platform (shared with the desktop)
const platform = new ServerPlatform();

// Create the HTTP server that serves the renderer bundle
const http = createHttpServer({ staticRoot: 'out/renderer' });

// Attach the WebSocket RPC server to the same listener
createWsServer(http, platform);

// Listen on the configured port (default 3000)
http.listen(3000, () => console.log('nodeterm server running on http://localhost:3000'));

Request Routing and Core Services

The src/server/handlers/ directory contains modular HTTP handlers for specific domain features such as file-system access, Git integration, download endpoints, and GitHub control. The main router in src/server/handlers/index.ts registers these handlers with the HTTP server, exposing them through the RPC layer to browser clients.

When the browser invokes operations like fs:list or git:status, these calls traverse the WebSocket connection to the ServerPlatform shim, which routes them to the appropriate handler in the core services layer. This architecture reuses the identical src/core/** modules employed by the desktop application, ensuring behavioral consistency across both editions.

// In the renderer (browser) side
window.nodeTerminal.fs.list('/home/user/project')
  .then((entries) => console.log('Project files:', entries));

Real-Time Agent Status Broadcasting

Live synchronization features such as unread badges and Kanban board updates rely on src/server/agent-status.ts. This module subscribes to the core's agent status events and mirrors them to connected browsers via the WebSocket infrastructure.

When the server-side platform emits an agent:status update, the broadcast function from src/server/ws.ts forwards the payload to all connected clients. This mechanism maintains real-time state synchronization across multiple browser sessions, replicating the live experience of the desktop edition without requiring Electron's main process.

// src/server/agent-status.ts
import { platform } from './platform-server';
import { broadcast } from './ws';

platform.on('agent:status', (status) => {
  broadcast('agent:status', status);   // forwards to all connected browsers
});

Summary

  • Static asset serving: src/server/http.ts delivers the Vite-compiled renderer bundle (out/renderer/) to browsers as static files, initiating the React application.
  • WebSocket RPC: The /ws endpoint in src/server/ws.ts implements the shared RPC protocol from src/shared/rpc.ts, replacing Electron's IPC with web-native sockets.
  • Platform abstraction: ServerPlatform in src/server/platform-server.ts implements the CorePlatform interface, isolating core logic from Electron APIs and enabling pure Node.js execution.
  • Service reuse: The Server Edition leverages the same src/core/** services as the desktop app, routing requests through src/server/handlers/index.ts to maintain feature parity.
  • Real-time sync: Agent status updates propagate to browsers via src/server/agent-status.ts, ensuring live UI elements remain synchronized across all connected clients.

Frequently Asked Questions

How does the Server Edition differ from the desktop Electron version?

The Server Edition replaces Electron's process boundaries with an HTTP and WebSocket stack. While the desktop version bundles the renderer in a native window using ipcMain/ipcRenderer for communication, the Server Edition serves the same React UI through a browser and multiplexes IPC calls over WebSocket connections via src/server/ws.ts.

What protocol does the browser use to communicate with the nodeterm server?

The browser communicates through a combination of standard HTTP for static assets and WebSocket for real-time RPC. Static files are served from src/server/http.ts, while the WebSocket endpoint at /ws (defined in src/server/ws.ts) handles all core service invocations using the protocol defined in src/shared/rpc.ts.

Can the Server Edition run without any Electron dependencies?

Yes. The ServerPlatform class in src/server/platform-server.ts implements the CorePlatform interface without importing Electron APIs. This allows the server to run in a pure Node.js environment, serving browsers while the core services remain identical to those used in the desktop application.

How are real-time updates synchronized across browser clients?

The server subscribes to core agent status events through src/server/agent-status.ts and forwards them to all connected browsers using the broadcast function from src/server/ws.ts. This ensures that live badges, unread dots, and Kanban board states remain synchronized across all active browser sessions without polling.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →