Tools

Runtime Environment

Understand Compozy's secure Bun runtime for executing TypeScript tools with configurable permissions and resource management

Overview

Compozy uses Bun as its JavaScript/TypeScript runtime environment, providing a fast, secure, and efficient execution platform for your tools. This guide explains the runtime architecture, security model, and configuration options for production deployments.

Lightning Fast

Bun's performance significantly reduces tool startup time and execution overhead

TypeScript Native

Run TypeScript directly without compilation steps or configuration complexity

Secure by Default

Fine-grained permission system with process isolation for each tool execution

Modern APIs

Support for latest JavaScript features and Web standard APIs out of the box

Architecture Overview

Process Isolation

Each tool execution runs in a separate Bun process, ensuring:

  • Complete isolation
    Between tool executions for maximum security
  • Memory protection
    Preventing cross-tool data leaks
  • Resource limits
    Enforced at the process level
  • Clean environment
    For each execution

Communication Protocol

Tools communicate through a simple JSON-based protocol:

Loading diagram...

Security Model

Permission System

Configure granular permissions for each tool based on its requirements:

File System Permissions

Control read and write access to specific directories:

runtime:
  permissions:
    - --allow-read=./data        # Read from data directory
    - --allow-write=./output     # Write to output directory
    - --deny-write=/etc          # Explicitly deny system directories
  • Use absolute paths
    For clarity and security
  • Start with minimal permissions
    Follow principle of least privilege
  • Explicitly deny sensitive directories
    Block access to system directories

Network Permissions

Restrict network access to specific domains:

runtime:
  permissions:
    - --allow-net=api.example.com     # Specific domain
    - --allow-net=*.trusted.com       # Wildcard subdomain
    - --allow-net=192.168.1.0/24      # IP range

Environment Variables

Control which environment variables tools can access:

runtime:
  permissions:
    - --allow-env=API_KEY,API_SECRET  # Specific variables
    - --allow-env=NODE_*              # Pattern matching
  • Only expose required variables
    Minimal environment access
  • Use patterns for related variable groups
    Organize with wildcards when appropriate
  • Never expose system environment wholesale
    Avoid broad environment access

Resource Limits

Prevent resource exhaustion with configurable limits:

runtime:
  limits:
    memory: "256MB"    # Maximum heap size

# Per-tool override
tools:
  heavy-processor:
    runtime:
      limits:
        memory: "1GB"  # Higher limit for specific tool

Recommended limits by use case:

  • Simple tools: 128MB - 256MB
  • Data processing: 512MB - 1GB
  • Heavy computation: 1GB - 2GB

Configuration Patterns

Optimized for rapid iteration and debugging:

# compozy.yaml (development)
runtime:
  type: bun
  entrypoint: "./tools/index.ts"

  permissions:
    - --allow-read       # Permissive for development
    - --allow-net        # All network access
    - --allow-env        # All environment variables

  limits:
    memory: "512MB"
    timeout: "60s"
    output_size: "20MB"

  debug:
    enabled: true
    log_level: "debug"

Key Features:

Permissive permissions

For faster development iteration

Higher resource limits

For debugging and development needs

Debug mode enabled

With detailed logging output

All access allowed

Network and environment variables

Best Practices

Tool Implementation Patterns

Every tool follows this pattern for reliable execution:

import { z } from 'zod';

// Define input/output schemas
const inputSchema = z.object({
  data: z.array(z.unknown()),
  operation: z.string()
});

const outputSchema = z.object({
  result: z.unknown(),
  metadata: z.object({
    processed: z.number(),
    duration: z.number()
  })
});

// Type definitions
type Input = z.infer<typeof inputSchema>;
type Output = z.infer<typeof outputSchema>;

// Main function
export async function processData(input: Input): Promise<Output> {
  const start = Date.now();

  // Validate input
  const validated = inputSchema.parse(input);

  // Process data
  const result = await performOperation(validated);

  // Return validated output
  return outputSchema.parse({
    result,
    metadata: {
      processed: validated.data.length,
      duration: Date.now() - start
    }
  });
}

Key Elements:

Zod schemas

For input/output validation

Type-safe interfaces

With TypeScript

Performance tracking

With execution timing

Structured metadata

In responses

Performance Optimization

  • Minimize Dependencies

    Keep tools lightweight by only importing necessary libraries

  • Cache Expensive Operations

    Implement caching for repeated expensive computations

  • Optimize Algorithms

    Profile and optimize hot code paths

  • Connection Pooling

    Reuse HTTP/database connections across requests

  • Async Operations

    Use concurrent processing where appropriate