Nodeterm Project File Model (V3): Workspace Index and Project Structure
Nodeterm's v3 project file model splits workspace data into a central index (workspace.json) stored in the user data directory and individual project files (.nodeterm/project.json) that contain serialized canvas state, separating project references from node data.
The eneskirca/nodeterm repository uses a sophisticated two-tier storage system in its v3 architecture. This design decouples the workspace index—which tracks project locations—from the actual project content, enabling efficient remote-SSH support and atomic saves. Understanding this structure is essential for developers integrating with nodeterm's storage layer or troubleshooting workspace issues.
The V3 Workspace Index (workspace.json)
The workspace index acts as the central registry for all projects without storing actual node data. According to the source code in src/core/workspace-files.ts, this file splits an in-memory workspace into the v3 index plus local project files for writing.
Index Location and Format
The index resides at app.getPath('userData')/workspace.json and follows this strict schema:
{
"version": 3,
"entries": [
{
"projectId": "project-1",
"cwd": "/home/user/my-repo"
},
{
"projectId": "project-2",
"ssh": {
"host": "example.com",
"user": "alice",
"port": 22
}
}
]
}
Each entry contains only the project identifier and connection details. The version: 3 field indicates the schema revision, as noted in src/main/index.ts at line 564.
Local vs. Remote References
The v3 index supports two distinct reference types:
- Local projects: Use the
cwdfield containing the absolute path to the project directory - Remote SSH projects: Use the
sshobject withhost,user, andportproperties
Neither entry type stores canvas data; both reference external .nodeterm/project.json files.
Project File Structure (.nodeterm/project.json)
Individual project files contain the complete canvas definition. The Project interface defined in src/shared/types.ts (lines 613-682) dictates the schema for these files.
Core Fields
| Field | Type | Purpose |
|---|---|---|
id |
string |
Stable UUID linking the project to its index entry |
title |
string |
Human-readable name displayed in the tab bar |
color |
string |
Hex color code for UI accents |
nodes |
NodeState[] |
Serialized React Flow nodes (terminals, stickers, groups) |
viewport |
Viewport |
Camera position and zoom level |
Optional Configuration
Project files may include additional metadata fields:
icon: Custom icon definition (seesrc/shared/project-icon.ts)collapsed: Boolean indicating sidebar tab statekanban: Kanban board configuration with columns and labelsdefaultPermissionMode: Agent permission handling settingsdefaultAccountId: Default Claude account for agent nodesdefaultProjectView: Enum value'canvas'or'kanban'for default viewsettings: Additional per-project settings (seeproject-settings.ts)
Data Flow: Loading, Saving, and Migration
The WorkspaceStore class in src/core/workspace-store.ts manages all v3 file operations, including the v2 to v3 migration logic at line 98.
Loading the Workspace
WorkspaceStore.load() executes a two-phase loading process:
- Reads
workspace.jsoninto memory - Iterates through
entriesand loads each.nodeterm/project.jsonfile referenced byprojectId
This separation allows nodeterm to load individual projects on demand rather than parsing a monolithic file.
Persisting Changes
The v3 model uses differential saving to minimize disk I/O:
WorkspaceStore.writeProject(): Updates only the specific.nodeterm/project.jsonfile when canvas data changesWorkspaceStore.saveIndex(): Rewritesworkspace.jsononly when the project list changes (add, remove, or reorder)
V2 to V3 Migration
On first run after upgrading, nodeterm executes an automatic migration:
- Assembles a v2 file from the legacy layout
- Writes the new v3 index to
workspace.json - Creates individual project files in their respective directories
- Backs up the original file with a
*.bakextension
The test suite in src/core/workspace-store.test.ts validates this round-trip conversion and migration flow.
Programmatic Usage Examples
Interact with the v3 model using the WorkspaceStore API:
import { WorkspaceStore } from './core/workspace-store';
// Load the complete workspace (index + all projects)
const ws = await WorkspaceStore.load();
// Retrieve a specific project
const project = await WorkspaceStore.readProject('project-1');
// Modify canvas data
project.nodes.push({
id: 'term-5',
kind: 'terminal',
data: { /* terminal config */ }
});
// Persist changes to the project file only
await WorkspaceStore.writeProject(project);
Inspect the index directly for debugging:
// Read workspace.json without loading projects
const index = await WorkspaceStore.readIndex();
console.log(index.version); // → 3
console.log(index.entries); // Array of project references
Create new projects programmatically:
const newProject = {
id: 'proj-new',
title: 'My New Canvas',
color: '#4A90E2',
nodes: [],
viewport: { x: 0, y: 0, zoom: 1 }
};
// Write the project file
await WorkspaceStore.writeProject(newProject);
// Register in the index
await WorkspaceStore.addIndexEntry({
projectId: newProject.id,
cwd: '/home/me/new-proj'
});
Key Source Files
src/shared/types.ts(lines 613-682): Defines theProjectinterface and field typessrc/core/workspace-files.ts: Contains the split logic separating index from project datasrc/core/workspace-store.ts(line 98): Implements loading, saving, and v2→v3 migrationsrc/core/workspace-store.test.ts: Unit tests for the v3 save/load round-tripsrc/main/index.ts(line 564): Documents the v3 index format
Summary
- The v3 model uses a split architecture:
workspace.jsonstores references while.nodeterm/project.jsonfiles store canvas data - The workspace index supports both local (
cwd) and remote (ssh) project references via theentriesarray - Project files contain React Flow nodes, viewport states, and optional kanban configurations according to the
Projectinterface WorkspaceStoreprovides atomic operations for reading individual projects without loading the entire workspace- Automatic migration converts v2 workspaces to v3 format, backing up legacy files before transformation
Frequently Asked Questions
Where is the nodeterm workspace index stored?
The v3 workspace index is stored at app.getPath('userData')/workspace.json, which resolves to the operating system's user data directory followed by the nodeterm application folder. This location ensures the index persists across application restarts while remaining separate from project-specific data.
What is the difference between the workspace index and project files in v3?
The workspace index (workspace.json) contains only lightweight metadata: the version number (3) and an array of entries mapping projectId values to either local directories (cwd) or SSH connections. Project files (.nodeterm/project.json) contain the heavy data: React Flow node states, viewport coordinates, kanban boards, and project settings. This separation enables nodeterm to load project lists instantly while deferring heavy canvas data loading until needed.
How does nodeterm handle remote SSH projects in the v3 model?
Remote projects use the ssh field in the index entry instead of cwd, specifying host, user, and port. The project file itself resides on the remote filesystem at .nodeterm/project.json relative to the SSH user's home directory or specified path. The v3 index tracks the connection parameters, while the remote filesystem stores the canvas data, allowing seamless switching between local and remote workspaces.
What happens during the v2 to v3 migration?
When nodetect detects a legacy v2 workspace, it automatically migrates data by parsing the old monolithic file, extracting individual projects, and writing them to separate .nodeterm/project.json files in their respective directories. It then creates the new v3 workspace.json index and backs up the original file with a .bak extension. This process is idempotent and preserves all project data while optimizing the storage structure for the new architecture.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →