File System and Terminals
This document explains how CoCalc handles file operations (read, write, listing, watching) and terminal sessions — the Conat service layer, the project daemon backend, and the frontend integration.
Overview
File operations and terminals both follow the same pattern: the frontend sends requests via Conat to the project daemon, which executes them on the local filesystem or PTY.
File Operations
System API
packages/conat/project/api/system.ts defines the project-level file API:
Streaming File Read/Write
For large files, CoCalc uses streaming via Conat requestMany:
Read (packages/conat/files/read.ts):
Write (packages/conat/files/write.ts):
These streaming APIs are used for:
HTTP download endpoints (serving files to browsers)
Copying files between projects
Large file transfers to/from compute servers
Copy Between Projects
File copying between projects (used by course assignments, etc.) uses webapp_client.project_client.copy_path_between_projects(), which coordinates Conat streaming between source and destination project daemons.
Directory Listings
Architecture
Directory listings use an interest-based watching system:
Key Components
Service (packages/conat/service/listings.ts):
Project implementation (packages/project/conat/listings.ts):
Listingsclass manages watched directoriesUses
MultipathWatcher(@cocalc/backend/path-watcher) for filesystem eventsStores results in a DKV (distributed key-value store):
Keys: directory paths
Values:
DirectoryListingEntry[](first ~300 files, sorted by recency)
Separate DKV for modification times
Frontend consumes the DKV for real-time file browser updates.
DirectoryListingEntry
Terminals
Architecture
Two communication channels:
DStream — streaming terminal I/O (character data)
Conat RPC — control commands (create, resize, kill)
Backend: Session
packages/project/conat/terminal/session.ts — the server-side terminal:
Key properties:
Uses
@lydell/node-ptyfor PTY managementDefault command:
/bin/bashInput truncation:
MAX_INPUT_SIZE = 10000(prevents paste-bomb crashes)Output throttling: configurable bytes/sec and messages/sec
History limit:
COCALC_TERMINAL_HISTORY_LIMIT_BYTES(default: 1MB)
Environment variables:
Backend: Manager
packages/project/conat/terminal/manager.ts — manages terminal sessions:
Creates/destroys terminal sessions on demand
Routes Conat service requests to the appropriate session
Handles terminal path naming
Conat Service API
packages/conat/service/terminal.ts — defines the RPC interface:
Both directions use createServiceClient / createServiceHandler from packages/conat/service/typed.ts.
Frontend: Terminal Component
packages/frontend/frame-editors/terminal-editor/ — the browser-side terminal:
connected-terminal.ts — Terminal class wrapping xterm.js:
Features:
xterm.js with WebGL rendering (
@xterm/addon-webgl)Auto-fit to container size (
@xterm/addon-fit)Clickable URLs (
@xterm/addon-web-links)Paste from system clipboard
Pause/resume output
Theme support (multiple terminal color schemes)
Reconnection on disconnect
conat-terminal.ts — ConatTerminal class managing the Conat connection:
Data flow:
User types → xterm.js
onData→ConatTerminal.write(data)ConatTerminalpublishes to DStreamProject
Sessionreceives from DStream → writes to PTYPTY output → project publishes to DStream
ConatTerminalreceives from DStream → emits"data"Terminalwrites to xterm.js display
Terminal Path Naming
Terminals are ephemeral by default (EPHEMERAL = true): faster, less server load, but history is lost when both project and browser close.
Terminal in Frame Editors
The terminal frame is defined in packages/frontend/frame-editors/terminal-editor/editor.ts and can be included in any editor spec:
Terminal Manager (Frontend)
packages/frontend/frame-editors/terminal-editor/terminal-manager.ts — manages multiple terminal instances per editor, one per frame ID.
Shell Execution
For non-interactive command execution (not a terminal), use the exec API:
Key Source Files
| File | Description |
|---|---|
packages/conat/project/api/system.ts | System API interface (listing, exec, file ops) |
packages/conat/files/read.ts | Streaming file read via Conat |
packages/conat/files/write.ts | Streaming file write via Conat |
packages/conat/service/terminal.ts | Terminal Conat service API |
packages/conat/service/listings.ts | Directory listings service API |
packages/project/conat/terminal/session.ts | PTY session (node-pty) |
packages/project/conat/terminal/manager.ts | Terminal session manager |
packages/project/conat/listings.ts | Directory watcher + DKV storage |
packages/frontend/frame-editors/terminal-editor/connected-terminal.ts | xterm.js wrapper |
packages/frontend/frame-editors/terminal-editor/conat-terminal.ts | Conat terminal connection |
packages/frontend/frame-editors/terminal-editor/terminal-manager.ts | Multi-terminal manager |
packages/frontend/frame-editors/terminal-editor/editor.ts | Terminal frame definition |
packages/frontend/frame-editors/terminal-editor/themes.ts | Terminal color themes |
packages/backend/path-watcher.ts | MultipathWatcher for filesystem events |
packages/util/terminal/names.ts | Terminal path utilities |