Skip to main content
The generators module provides functions to create all supporting files for a complete OpenClaw stack deployment: environment files, shell scripts, proxy configs, monitoring dashboards, and more.

Overview

Generators transform a ResolverOutput into specific file content. The main generate() function orchestrates all generators, but you can use individual generators directly.
import {
  generateEnvFiles,
  generateCaddyfile,
  generateScripts,
  generateReadme
} from '@better-openclaw/core';

Environment Files

generateEnvFiles

Generates .env.example and .env files with all required environment variables.
import { generateEnvFiles } from '@better-openclaw/core';
import type { EnvGeneratorOptions } from '@better-openclaw/core';

const { envExample, env } = generateEnvFiles(resolved, {
  generateSecrets: true,
  domain: 'example.com',
  openclawVersion: 'latest',
  composeFiles: ['docker-compose.yml', 'docker-compose.ai.yml'],
  composeProfiles: ['ai', 'media']
});

await writeFile('.env.example', envExample);
await writeFile('.env', env);
resolved
ResolverOutput
required
Resolved service configuration
options
EnvGeneratorOptions
required
Generation options
options.generateSecrets
boolean
required
Auto-generate cryptographically random secrets
options.domain
string
Domain for reverse proxy
options.openclawVersion
string
OpenClaw version tag
options.composeFiles
string[]
Compose file names for COMPOSE_FILE env var
options.composeProfiles
string[]
Profile names for COMPOSE_PROFILES env var
options.nativeServiceIds
Set<string>
Service IDs running natively on host (for bare-metal)
options.openclawImage
OpenclawImageVariant
Image variant (“official”, “coolify”, “alpine”)
Returns: { envExample: string, env: string }

getStructuredEnvVars

Returns structured environment variables grouped by service.
import { getStructuredEnvVars } from '@better-openclaw/core';
import type { EnvVarGroup } from '@better-openclaw/core';

const groups: EnvVarGroup[] = getStructuredEnvVars(resolved, options);

groups.forEach(group => {
  console.log(`${group.serviceName}:`);
  group.variables.forEach(v => {
    console.log(`  ${v.key}=${v.value}`);
  });
});
Returns: Array of EnvVarGroup objects with serviceName and variables array.

Reverse Proxy Configs

generateCaddyfile

Generates a complete Caddyfile with reverse proxy routes for all services.
import { generateCaddyfile } from '@better-openclaw/core';

const caddyfile = generateCaddyfile(resolved, 'example.com');
await writeFile('caddy/Caddyfile', caddyfile);
resolved
ResolverOutput
required
Resolved services
domain
string
required
Main domain (e.g., “example.com”)
Returns: Caddyfile content as string Generated routes:
  • service-id.example.com → service primary port
  • service-id-alt.example.com → additional exposed ports
  • example.com → OpenClaw gateway

generateTraefikConfig

Generates Traefik static config and dynamic service labels.
import { generateTraefikConfig } from '@better-openclaw/core';

// Called automatically by compose() when proxy: 'traefik'
const { staticConfig, serviceLabels } = generateTraefikConfig(resolved, 'example.com');

await writeFile('traefik/traefik.yml', staticConfig);
// serviceLabels are injected into docker-compose service definitions
Note: Traefik labels are automatically added to services via the composer. You typically don’t call this directly.

Shell Scripts

generateScripts

Generates helper shell scripts for managing the stack.
import { generateScripts } from '@better-openclaw/core';

const scripts = generateScripts();

for (const [path, content] of Object.entries(scripts)) {
  await writeFile(path, content, { mode: 0o755 });
}
Returns: Record<string, string> with these files:
  • scripts/start.sh - Start all services (validates prereqs, generates secrets)
  • scripts/stop.sh - Stop all services gracefully
  • scripts/restart.sh - Restart all services
  • scripts/logs.sh - View service logs
  • scripts/backup.sh - Backup volumes and configs
  • scripts/restore.sh - Restore from backup
  • scripts/update.sh - Pull latest images and restart

generateHealthCheck

Generates stack-specific health check scripts.
import { generateHealthCheck } from '@better-openclaw/core';

const healthCheckFiles = generateHealthCheck(resolved, {
  projectName: 'my-stack',
  deploymentType: 'docker'
});

for (const [path, content] of Object.entries(healthCheckFiles)) {
  await writeFile(path, content, { mode: 0o755 });
}
Returns: Record<string, string> with:
  • scripts/health-check.sh - Comprehensive health check for all services
  • scripts/health-check.ps1 - Windows PowerShell version

PostgreSQL

generatePostgresInit

Generates a database initialization script for services that need dedicated PostgreSQL databases.
import { generatePostgresInit } from '@better-openclaw/core';

const initScript = generatePostgresInit(resolved);
if (initScript) {
  await writeFile('postgres/init-databases.sh', initScript, { mode: 0o755 });
}
Returns: Shell script content or null if no PostgreSQL What it does:
  • Creates database users for each service
  • Creates dedicated databases
  • Grants privileges
  • Idempotent (safe to run multiple times)

getDbRequirements

Returns which services need dedicated PostgreSQL databases.
import { getDbRequirements } from '@better-openclaw/core';

const dbReqs = getDbRequirements(resolved);

dbReqs.forEach(req => {
  console.log(`${req.serviceId} needs DB: ${req.dbName}`);
  console.log(`  User: ${req.dbUser}`);
  console.log(`  Password env: ${req.passwordEnvVar}`);
});
Returns: Array of { serviceId, dbName, dbUser, passwordEnvVar }

Monitoring

generatePrometheusConfig

Generates Prometheus configuration with service discovery.
import { generatePrometheusConfig } from '@better-openclaw/core';

const hasPrometheus = resolved.services.some(s => s.definition.id === 'prometheus');
if (hasPrometheus) {
  const config = generatePrometheusConfig(resolved);
  await writeFile('prometheus/prometheus.yml', config);
}
Returns: prometheus.yml content with scrape configs for all services

generateGrafanaConfig

Generates Grafana datasource and provisioning configs.
import { generateGrafanaConfig } from '@better-openclaw/core';

const hasGrafana = resolved.services.some(s => s.definition.id === 'grafana');
if (hasGrafana) {
  const grafanaFiles = generateGrafanaConfig();
  for (const [path, content] of Object.entries(grafanaFiles)) {
    await writeFile(path, content);
  }
}
Returns: Record<string, string> with:
  • config/grafana/datasources/prometheus.yml
  • config/grafana/dashboards/dashboard.yml

generateGrafanaDashboard

Generates a pre-configured OpenClaw stack overview dashboard.
import { generateGrafanaDashboard } from '@better-openclaw/core';

const dashboard = generateGrafanaDashboard();
await writeFile('config/grafana/dashboards/openclaw-stack-overview.json', dashboard);
Returns: Grafana dashboard JSON

Workflow Automation

generateN8nWorkflows

Generates starter n8n workflows for common automation tasks.
import { generateN8nWorkflows } from '@better-openclaw/core';

const n8nWorkflows = generateN8nWorkflows(resolved);
for (const [path, content] of Object.entries(n8nWorkflows)) {
  await writeFile(path, content);
}
Returns: Record<string, string> with workflow JSON files in n8n/workflows/

Skills

generateSkillFiles

Generates OpenClaw skill configuration files.
import { generateSkillFiles } from '@better-openclaw/core';

const skillFiles = generateSkillFiles(resolved);
for (const [path, content] of Object.entries(skillFiles)) {
  await writeFile(path, content);
}
Returns: Record<string, string> with skill manifest files

Documentation

generateReadme

Generates a comprehensive README.md for the stack.
import { generateReadme } from '@better-openclaw/core';

const readme = generateReadme(resolved, {
  projectName: 'my-stack',
  domain: 'example.com',
  proxy: 'caddy',
  deploymentType: 'docker',
  hasNativeServices: false,
  openclawInstallMethod: 'docker'
});

await writeFile('README.md', readme);
resolved
ResolverOutput
required
Resolved services
options.projectName
string
required
Project name
options.domain
string
Domain name
options.proxy
ProxyType
Proxy type
options.deploymentType
DeploymentType
required
Deployment method
options.hasNativeServices
boolean
default:"false"
Whether native services are included
options.openclawInstallMethod
OpenclawInstallMethod
OpenClaw install method
Returns: Complete README.md content with:
  • Quick start instructions
  • Service list with URLs
  • Configuration guide
  • Troubleshooting tips

generateStackManifest

Generates a machine-readable stack manifest for Mission Control.
import { generateStackManifest } from '@better-openclaw/core';
import type { StackManifest } from '@better-openclaw/core';

const manifestFiles = generateStackManifest(resolved, input);
for (const [path, content] of Object.entries(manifestFiles)) {
  await writeFile(path, content);
}
Returns: Record<string, string> with stack-manifest.json

Cloud & Bare-Metal

generateCloudInit

Generates a cloud-init configuration for automated VPS deployment.
import { generateCloudInit } from '@better-openclaw/core';

const cloudInit = generateCloudInit({
  composeYaml: composeResult.files['docker-compose.yml'],
  envContent: envFiles.env,
  projectName: 'my-stack',
  gatewayPort: 18789
});

await writeFile('cloud-init.yml', cloudInit);
Returns: cloud-init YAML for VPS provisioning

generateBareMetalInstall

Generates bare-metal installation scripts.
import { generateBareMetalInstall } from '@better-openclaw/core';

const bareMetalFiles = generateBareMetalInstall({
  platform: 'linux/amd64',
  projectName: 'my-stack',
  hasNativeServices: true
});

for (const [path, content] of Object.entries(bareMetalFiles)) {
  await writeFile(path, content);
}

generateNativeInstallScripts

Generates native service install scripts for bare-metal deployments.
import { generateNativeInstallScripts } from '@better-openclaw/core';

const nativeScripts = generateNativeInstallScripts({
  nativeServices: partition.nativeServices,
  platform: 'linux',
  projectName: 'my-stack'
});

for (const [path, content] of Object.entries(nativeScripts)) {
  await writeFile(path, content, { mode: 0o755 });
}

Main Orchestrator

generate

Orchestrates all generators to create a complete stack.
import { generate } from '@better-openclaw/core';
import type { GenerationInput, GenerationResult } from '@better-openclaw/core';

const result: GenerationResult = generate({
  projectName: 'my-stack',
  services: ['redis', 'postgresql', 'n8n'],
  skillPacks: ['ai-toolkit'],
  proxy: 'caddy',
  domain: 'example.com',
  platform: 'linux/amd64',
  deploymentType: 'docker',
  deployment: 'local',
  generateSecrets: true,
  monitoring: true
});

console.log('Generated files:', Object.keys(result.files).length);
console.log('Service count:', result.metadata.serviceCount);
console.log('Skill count:', result.metadata.skillCount);
console.log('Memory estimate:', result.metadata.estimatedMemoryMB, 'MB');

// Write all files
for (const [path, content] of Object.entries(result.files)) {
  await writeFile(path, content);
}
See Generation API for complete details.

Types

EnvVarGroup

interface EnvVarGroup {
  serviceName: string;
  serviceId: string;
  variables: Array<{
    key: string;
    value: string;
    secret: boolean;
    description: string;
  }>;
}

StackManifest

interface StackManifest {
  version: string;
  projectName: string;
  services: StackManifestService[];
  skills: StackManifestSkill[];
  generated: string;
}

Examples

Custom Environment Generation

import { getStructuredEnvVars } from '@better-openclaw/core';

const groups = getStructuredEnvVars(resolved, {
  generateSecrets: true,
  domain: 'example.com'
});

// Filter only secrets
const secrets = groups.flatMap(g => 
  g.variables.filter(v => v.secret)
);

console.log('Secrets to configure:');
secrets.forEach(s => {
  console.log(`  ${s.key}: ${s.description}`);
});

Selective File Generation

import {
  generateEnvFiles,
  generateScripts,
  generateReadme,
  generateCaddyfile
} from '@better-openclaw/core';

// Only generate what you need
const files: Record<string, string> = {};

const { env, envExample } = generateEnvFiles(resolved, options);
files['.env'] = env;
files['.env.example'] = envExample;

const scripts = generateScripts();
Object.assign(files, scripts);

const readme = generateReadme(resolved, readmeOptions);
files['README.md'] = readme;

if (input.proxy === 'caddy') {
  files['caddy/Caddyfile'] = generateCaddyfile(resolved, input.domain!);
}

See Also

Build docs developers (and LLMs) love