Skip to main content

Overview

The Runtime interface defines how and where agent sessions execute. Runtimes provide isolated execution environments and handle process lifecycle, I/O, and resource management. Plugin Slot: runtime
Default Plugin: tmux

Interface Definition

export interface Runtime {
  readonly name: string;
  
  create(config: RuntimeCreateConfig): Promise<RuntimeHandle>;
  destroy(handle: RuntimeHandle): Promise<void>;
  sendMessage(handle: RuntimeHandle, message: string): Promise<void>;
  getOutput(handle: RuntimeHandle, lines?: number): Promise<string>;
  isAlive(handle: RuntimeHandle): Promise<boolean>;
  getMetrics?(handle: RuntimeHandle): Promise<RuntimeMetrics>;
  getAttachInfo?(handle: RuntimeHandle): Promise<AttachInfo>;
}

Methods

name
string
required
Plugin name identifier (e.g. "tmux", "docker", "kubernetes").
create
(config: RuntimeCreateConfig) => Promise<RuntimeHandle>
required
Create a new session environment and return a handle for communication.Parameters:
  • config.sessionId - Unique session identifier
  • config.workspacePath - Path to workspace directory
  • config.launchCommand - Shell command to launch the agent
  • config.environment - Environment variables for the agent process
Returns: RuntimeHandle for the created environment
destroy
(handle: RuntimeHandle) => Promise<void>
required
Destroy a session environment and clean up resources.Parameters:
  • handle - Runtime handle from create()
sendMessage
(handle: RuntimeHandle, message: string) => Promise<void>
required
Send a text message/prompt to the running agent.Parameters:
  • handle - Runtime handle
  • message - Text to send to the agent
getOutput
(handle: RuntimeHandle, lines?: number) => Promise<string>
required
Capture recent output from the session.Parameters:
  • handle - Runtime handle
  • lines - Optional: number of recent lines to return
Returns: String containing session output
isAlive
(handle: RuntimeHandle) => Promise<boolean>
required
Check if the session environment is still alive.Parameters:
  • handle - Runtime handle
Returns: true if environment is running, false otherwise
getMetrics
(handle: RuntimeHandle) => Promise<RuntimeMetrics>
Optional: Get resource metrics (uptime, memory, CPU usage).Parameters:
  • handle - Runtime handle
Returns: RuntimeMetrics with resource usage data
getAttachInfo
(handle: RuntimeHandle) => Promise<AttachInfo>
Optional: Get info needed to attach a human to this session (for Terminal plugin).Parameters:
  • handle - Runtime handle
Returns: AttachInfo with connection details

RuntimeCreateConfig

export interface RuntimeCreateConfig {
  sessionId: SessionId;
  workspacePath: string;
  launchCommand: string;
  environment: Record<string, string>;
}
Configuration passed to create() when spawning a new runtime environment.
sessionId
SessionId
required
Unique session identifier
workspacePath
string
required
Absolute path to workspace directory where agent will execute
launchCommand
string
required
Shell command to launch the agent (from Agent.getLaunchCommand())
environment
Record<string, string>
required
Environment variables for the agent process (from Agent.getEnvironment())

RuntimeHandle

export interface RuntimeHandle {
  id: string;
  runtimeName: string;
  data: Record<string, unknown>;
}
Opaque handle returned by create(), used for all subsequent operations.
id
string
required
Runtime-specific identifier (tmux session name, container ID, pod name, etc.)
runtimeName
string
required
Which runtime created this handle (matches Runtime.name)
data
Record<string, unknown>
required
Runtime-specific data (ports, connection strings, etc.)

RuntimeMetrics

export interface RuntimeMetrics {
  uptimeMs: number;
  memoryMb?: number;
  cpuPercent?: number;
}
uptimeMs
number
required
How long the environment has been running (milliseconds)
memoryMb
number
Memory usage in megabytes
cpuPercent
number
CPU usage percentage (0-100)

AttachInfo

export interface AttachInfo {
  type: "tmux" | "docker" | "ssh" | "web" | "process";
  target: string;
  command?: string;
}
type
string
required
How to connect: "tmux", "docker", "ssh", "web", or "process"
target
string
required
Connection target:
  • For tmux: session name
  • For docker: container ID
  • For web: URL
  • For SSH: host string
command
string
Optional command to run to attach (e.g. tmux attach -t session-name)

Usage Examples

Implementing a Runtime Plugin

import type { Runtime, RuntimeHandle, RuntimeCreateConfig } from "@composio/ao-core";
import { execFile } from "node:child_process";
import { promisify } from "node:util";

const execFileAsync = promisify(execFile);

export function create(): Runtime {
  return {
    name: "tmux",
    
    async create(config: RuntimeCreateConfig): Promise<RuntimeHandle> {
      const { sessionId, workspacePath, launchCommand, environment } = config;
      
      // Create tmux session
      await execFileAsync("tmux", [
        "new-session",
        "-d",
        "-s", sessionId,
        "-c", workspacePath
      ], { timeout: 30_000 });
      
      // Set environment variables
      for (const [key, value] of Object.entries(environment)) {
        await execFileAsync("tmux", [
          "set-environment",
          "-t", sessionId,
          key, value
        ], { timeout: 5_000 });
      }
      
      // Launch agent
      await execFileAsync("tmux", [
        "send-keys",
        "-t", sessionId,
        launchCommand,
        "Enter"
      ], { timeout: 5_000 });
      
      return {
        id: sessionId,
        runtimeName: "tmux",
        data: {}
      };
    },
    
    async destroy(handle: RuntimeHandle): Promise<void> {
      await execFileAsync("tmux", ["kill-session", "-t", handle.id], {
        timeout: 5_000
      });
    },
    
    async sendMessage(handle: RuntimeHandle, message: string): Promise<void> {
      await execFileAsync("tmux", [
        "send-keys",
        "-t", handle.id,
        message,
        "Enter"
      ], { timeout: 5_000 });
    },
    
    async getOutput(handle: RuntimeHandle, lines = 100): Promise<string> {
      const { stdout } = await execFileAsync("tmux", [
        "capture-pane",
        "-t", handle.id,
        "-p",
        "-S", `-${lines}`
      ], { timeout: 5_000 });
      return stdout;
    },
    
    async isAlive(handle: RuntimeHandle): Promise<boolean> {
      try {
        await execFileAsync("tmux", ["has-session", "-t", handle.id], {
          timeout: 5_000
        });
        return true;
      } catch {
        return false;
      }
    }
  };
}

Using Runtime in Session Manager

import type { Runtime, RuntimeCreateConfig } from "@composio/ao-core";

const runtime: Runtime = registry.get("runtime", "tmux");

const createConfig: RuntimeCreateConfig = {
  sessionId: "my-app-1",
  workspacePath: "/workspace/my-app-1",
  launchCommand: "claude --project . --model claude-sonnet-4-20250514",
  environment: {
    ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY!,
    SESSION_ID: "my-app-1"
  }
};

const handle = await runtime.create(createConfig);

// Later: send a message
await runtime.sendMessage(handle, "Fix the authentication bug");

// Check if still alive
if (await runtime.isAlive(handle)) {
  console.log("Session is running");
}

// Clean up
await runtime.destroy(handle);

Implementation Notes

Security Considerations

  • Always use execFile instead of exec to prevent shell injection
  • Validate all handle IDs before using in shell commands
  • Set timeouts on all external command executions
  • Sanitize environment variables to prevent code injection

Error Handling

  • Throw errors if runtime operations fail (creation, destruction, messaging)
  • Return false from isAlive() for dead environments (don’t throw)
  • Handle network errors gracefully for remote runtimes (docker, k8s, SSH)

Built-in Plugins

  • tmux - Local tmux sessions (default)
  • process - Direct Node.js child processes
Future plugins could support Docker, Kubernetes, AWS ECS, SSH remote hosts, cloud sandboxes, etc.

See Also

  • Agent - Agent plugin interface
  • Session - Session interface
  • Terminal - Terminal UI plugin interface

Build docs developers (and LLMs) love