Preparing your workspace...

assistant-chat.tsx2.5k
utils.ts850
button.tsx720
Quick Actions
codmir
Docs
Discord
Get started
API
  • Introduction
  • Installation
  • Your First Project
  • Your First Agent

Remote development environments and distributed job execution across Linux nodes.

Cluster SDK

The Cluster SDK (@codmir/cluster-sdk) enables remote development environments and distributed job execution across a pool of Linux machines.

Installation

pnpm add @codmir/cluster-sdk

Quick Start

import { createClusterClient } from '@codmir/cluster-sdk';

const client = createClusterClient({
  baseUrl: 'https://codmir.com/api/cluster',
  token: 'your-auth-token',
});

// Create a dev session (SSH mode)
const session = await client.sessions.create({
  repoUrl: 'https://github.com/org/repo',
  mode: 'ssh',
});

// Get SSH command
console.log(session.sshInfo?.sshCommand);
// ssh -p 22 [email protected] -t "cd /var/codmir/workspaces/sess_abc123/repo && exec $SHELL -l"

Two IDE Modes

SSH Mode

Use your local IDE (VS Code, Windsurf, JetBrains) with remote workspace:

const session = await client.sessions.create({
  repoUrl: 'https://github.com/org/repo',
  mode: 'ssh',
});

// Copy to clipboard
console.log(session.sshInfo?.sshCommand);

// Or get VS Code SSH config
console.log(session.sshInfo?.vscodeSshConfig);
// Host codmir-sess_abc123
//   HostName 192.168.1.10
//   Port 22
//   User codmir

Browser Mode

VS Code in your browser via code-server:

const session = await client.sessions.create({
  repoUrl: 'https://github.com/org/repo',
  mode: 'browser',
});

// Open in browser
window.open(session.browserInfo?.ideUrl);

// Password if required
console.log(session.browserInfo?.password);

Running Jobs

Execute builds, tests, and other tasks on the cluster:

const job = await client.jobs.run({
  repoUrl: 'https://github.com/org/repo',
  command: 'pnpm install && pnpm build',
});

console.log(job.id, job.status);

Stream Job Logs

const abort = client.jobs.streamLogs(job.id, {
  onEvent: (event) => {
    if ('line' in event) {
      console.log(`[${event.stream}] ${event.line}`);
    }
    if ('status' in event) {
      console.log(`Job ${event.status}`);
    }
  },
  onClose: () => console.log('Stream closed'),
});

// Cancel streaming
abort();

Job with Patch

Apply uncommitted changes before running:

const job = await client.jobs.run({
  repoUrl: 'https://github.com/org/repo',
  command: 'pnpm test',
  patch: `
diff --git a/src/app.ts b/src/app.ts
--- a/src/app.ts
+++ b/src/app.ts
@@ -1 +1 @@
-const x = 1;
+const x = 2;
`,
});

API Reference

Sessions

// Create session
client.sessions.create({
  repoUrl: string;      // Git repository URL
  ref?: string;         // Branch, tag, or commit
  mode: 'ssh' | 'browser';
  labels?: string[];    // Prefer nodes with labels
}): Promise<ClusterSession>

// Get session
client.sessions.get(sessionId: string): Promise<ClusterSession>

// Terminate session
client.sessions.terminate(sessionId: string, force?: boolean): Promise<void>

// List user's sessions
client.sessions.list(): Promise<ClusterSession[]>

Jobs

// Run job
client.jobs.run({
  repoUrl: string;
  ref?: string;
  command: string;
  cwd?: string;           // Relative to workspace
  env?: Record<string, string>;
  timeout?: number;       // ms, default 300000
  patch?: string;         // Git diff to apply
  sessionId?: string;     // Run on session's node
}): Promise<ClusterJob>

// Get job
client.jobs.get(jobId: string): Promise<ClusterJob>

// Cancel job
client.jobs.cancel(jobId: string, reason?: string): Promise<void>

// Stream logs (SSE)
client.jobs.streamLogs(jobId: string, handler: {
  onEvent: (event: JobLogEvent | JobStatusEvent) => void;
  onError?: (error: Error) => void;
  onClose?: () => void;
}): () => void  // Returns abort function

Nodes

// List nodes
client.nodes.list(): Promise<ClusterNode[]>

// Get node
client.nodes.get(nodeId: string): Promise<ClusterNode>

Types

ClusterSession

interface ClusterSession {
  id: string;
  userId: string;
  nodeId: string;
  mode: 'ssh' | 'browser';
  status: 'pending' | 'provisioning' | 'ready' | 'active' | 'terminating' | 'terminated' | 'error';
  context: {
    repoUrl: string;
    ref?: string;
  };
  workspacePath: string;
  sshInfo?: {
    host: string;
    port: number;
    user: string;
    workspacePath: string;
    sshCommand: string;
    vscodeSshConfig: string;
  };
  browserInfo?: {
    ideUrl: string;
    password?: string;
  };
  createdAt: Date;
  error?: string;
}

ClusterJob

interface ClusterJob {
  id: string;
  userId: string;
  nodeId?: string;
  sessionId?: string;
  status: 'queued' | 'assigned' | 'running' | 'completed' | 'failed' | 'cancelled';
  request: {
    repoUrl: string;
    command: string;
    // ...
  };
  exitCode?: number;
  output?: string;
  startedAt?: Date;
  completedAt?: Date;
  error?: string;
}

ClusterNode

interface ClusterNode {
  id: string;
  hostname: string;
  status: 'online' | 'offline' | 'busy' | 'draining' | 'maintenance';
  labels: string[];
  metrics?: {
    cpuUsage: number;
    memoryUsedMb: number;
    memoryTotalMb: number;
    loadAverage: [number, number, number];
    runningSessions: number;
    runningJobs: number;
  };
}

Helpers

import {
  generateSshCommand,
  generateVscodeSshConfig,
  getBrowserIdeUrl,
} from '@codmir/cluster-sdk';

// Generate SSH command
const cmd = generateSshCommand(session);

// Generate VS Code config stanza
const config = generateVscodeSshConfig(session);

// Get browser IDE URL
const url = getBrowserIdeUrl(session);

Error Handling

import { ClusterApiError, ClusterConnectionError } from '@codmir/cluster-sdk';

try {
  await client.sessions.create({ ... });
} catch (error) {
  if (error instanceof ClusterApiError) {
    // API returned error response
    console.log(error.status);  // 400, 401, 404, etc.
    console.log(error.message);
    console.log(error.details);
  }
  if (error instanceof ClusterConnectionError) {
    // Network/connection error
    console.log(error.message);
    console.log(error.cause);
  }
}

Configuration

const client = createClusterClient({
  baseUrl: string;      // API base URL
  token?: string;       // Auth token
  timeout?: number;     // Request timeout (default 30000)
  onError?: (error: Error) => void;  // Global error handler
});

Deployment Modes

Local Mode (Self-hosted)

Direct SSH execution from the Next.js app:

CLUSTER_EXECUTION_MODE=local

Best for development and self-hosted deployments with no timeout constraints.

Cloud Mode (Vercel + Railway)

Jobs queued in Redis, executed by Railway worker:

CLUSTER_EXECUTION_MODE=cloud
CLUSTER_WORKER_URL=https://your-worker.railway.app
CLUSTER_WEBHOOK_SECRET=your-secret
REDIS_URL=redis://...

Best for production Vercel deployments where jobs may exceed the 60s timeout.

Server Setup

See Cluster Documentation for setting up cluster nodes and Railway workers.

Open in ChatGPTOpen in ClaudeConnect MCP on CursorConnect MCP on WindsurfEdit on GitHub
codmir
Products
Desktop AppMobile AppIDE ExtensionAI AgentsOverseerVoice ModeCortex ProtocolHive MindGame Dev (Godat)PricingDownload
Solutions
AI Code AgentsCode ReviewError TrackingSelf-HealingDeploy TrackingAI Tracking SDKWorkflow AutomationTesting FrameworkTime TrackingVoice Control
Platform
ProjectsTickets & BoardsAgent MarketplaceIntegrationsTemplatesApp HubAdmin PanelAnalytics
Integrations
GitHubSlackDiscordVercelSentryRailwayLinearAll Integrations
Developers
DocumentationAPI ReferenceSDKCLIDeveloper PortalMarketplaceMCP ConnectorsWebhooksExamplesnpm Packages
Resources
BlogChangelogCommunityTutorialsGet StartedSupportStatusFeedback
Company
AboutCareersContact SalesKickstarterReferral Program
Legal
Terms of UsePrivacy PolicyEULATrademarkSecurity
Download on the App StoreGet it on Google Play

Codmir™ 2026. All rights reserved.

Free & open source SDK — Apache 2.0 License