Developer section: these pages cover the S6S workflow engine for self-hosted installs and developers. On s6s.ai, API keys and MCP access are issued by S6S on request (contact us); on a self-hosted install, an admin creates them on the API Keys page. For the AI Visibility product, start at the AI Visibility docs.

Self-Hosting

Run S6S on your own infrastructure. Full control over data, credentials, and execution.

Overview

S6S is source-available under the Business Source License 1.1 (see LICENSE in the repository for the production-use grant) and can be self-hosted on any machine that runs Docker or Node.js. There are two ways to get started:

  • Docker Compose (recommended) — PostgreSQL, the web app and the worker in two containers. You supply three settings in a .env file.
  • Manual setup — install Node.js, pnpm, and PostgreSQL yourself.

Cloud vs Self-hosted

Self-hosted (community edition)

  • 32 node types, 23 executors (Slack, Gmail, YouTube, Buffer, HTTP, Database, AI agent…)
  • Full compilation pipeline, worker daemon, scheduling
  • REST API, TypeScript SDK, MCP server
  • Canvas editor, chat builder (bring your own AI provider)
  • OAuth + API key credential management
  • action.http for calling any REST API

S6S Cloud Cloud

  • Everything in self-hosted, plus:
  • AI Visibility Monitor (track brand mentions across AI engines)
  • Dynamic integration learning (unknown APIs auto-discovered)
  • Managed LLM for Ali — no keys needed
  • Hosted infrastructure, zero ops

Docker Compose (recommended)

The fastest way to run S6S. You need Docker with Compose v2, openssl, and access to the source repository, which is private during the private beta (ask S6S for access). Create a .env file with three settings, then start:

Terminal
git clone https://github.com/Sawan6/S6S-ai.git
cd S6S-ai

# The three settings the server needs before it will start
cat > .env <<EOF
S6S_CREDENTIAL_ENCRYPTION_KEY=$(openssl rand -hex 32)
S6S_JWT_SECRET=$(openssl rand -hex 32)
S6S_PUBLIC_REGISTRATION=true
EOF

docker compose up -d

Why these three settings

The image runs in production mode (NODE_ENV=production), and in production the server refuses to start unless all of the following hold:

  • S6S_CREDENTIAL_ENCRYPTION_KEY is exactly 64 hex characters.
  • S6S_JWT_SECRET is set. Use a second, different random value.
  • One registration gate is set: S6S_PUBLIC_REGISTRATION=true, S6S_ALLOWED_EMAILS, or S6S_INVITE_CODE. The stock docker-compose.yml forwards all three (see what Compose forwards).
  • S6S_AUTH_DISABLED and S6S_ALLOW_PRIVATE_URLS are not true.
  • No secret contains placeholder text: placeholder, changeme, change-me, replace, or a leading your-.

If a check fails, the server process exits, Compose restarts the container in a loop, and docker compose logs s6s shows the reason. Do not copy .env.example for Docker: its secrets are placeholders that fail this check, and it also sets S6S_LIVE_EXECUTION=false and S6S_BASE_URL=https://s6s.ai, which Compose would forward.

This starts:

  • PostgreSQL 16 with a persistent volume (pgdata). Compose also publishes it on host port 5432 with the fixed password written in docker-compose.yml, so block that port from other machines.
  • S6S (web app + worker daemon in one container) on port 3000, published on all host interfaces.
  • On every start, migrations run first, then the demo workflows are seeded. Seeding does not create duplicates, but it re-enables any demo workflow you disabled; set S6S_SEED_DEMO_WORKFLOWS=false to turn it off.

Then open http://localhost:3000/signup on the same machine and create your account. The community edition's home is the workflow dashboard at /dashboard.

Before anyone else can reach port 3000: with S6S_PUBLIC_REGISTRATION=true and no allowlist or invite code, anyone who can reach the port can create an account, and in the community edition every account can change platform-wide settings such as the AI provider. Sign-in also needs HTTPS on any address other than localhost, because the session cookie is marked Secure. For anything beyond a local trial, switch to S6S_ALLOWED_EMAILS or S6S_INVITE_CODE in .env and work through the production checklist.

Configuration

How settings reach S6S depends on how you run it:

  • Docker Compose reads .env in the project folder only to fill the ${…} placeholders in docker-compose.yml. A variable reaches the container only if docker-compose.yml lists it under environment:, and .env itself is excluded from the image. Any other variable you put in .env is silently ignored.
  • Manual setup: the web app and the worker read the root .env directly; the migration script does not (see Manual Setup).

What the stock docker-compose.yml forwards

VariableWhen not set in .envDescription
DATABASE_URLFixedThe bundled postgres service. A value in .env does not change it.
NODE_ENVproductionFixed. Turns on the start-up checks above.
S6S_LOG_FORMATjsonFixed.
S6S_CREDENTIAL_ENCRYPTION_KEYemptyRequired: the server will not start while it is empty.
S6S_JWT_SECRETemptyRequired: the server will not start while it is empty.
S6S_ALLOWED_EMAILSemptyRegistration gate: only these emails (comma-separated) may sign up or sign in.
S6S_INVITE_CODEemptyRegistration gate: new sign-ups need this code.
S6S_PUBLIC_REGISTRATIONfalseRegistration gate: true opens sign-up to anyone. One of the three gates must be set.
S6S_OPERATOR_EMAILSemptyThese emails get the admin role when they sign in with Google or GitHub (accounts without a password).
S6S_BASE_URLhttp://localhost:3000Set your public URL in production.
S6S_LIVE_EXECUTIONtrueIntegration steps call real services.
S6S_AUTH_DISABLEDfalseMust stay off in production.
S6S_SEED_DEMO_WORKFLOWStrueSeed demo workflows on every start.
S6S_WORKER_DAEMON_ENABLEDtrueStart the worker inside the container.
S6S_EDITIONemptyCommunity edition.
GOOGLE_CLIENT_ID / _SECRETemptyGoogle sign-in.
GITHUB_CLIENT_ID / _SECRETemptyGitHub sign-in.
OAUTH_GOOGLE_CLIENT_ID / _SECRETemptyGoogle integration connections (Drive, Sheets, Gmail, YouTube).
S6S_PLATFORM_LLM_PROVIDERemptyopenai or anthropic: the AI provider for Ali and action.ai. Empty = the provider saved in Settings.
S6S_PLATFORM_LLM_MODELemptyOptional model for that provider.
S6S_OPENAI_API_KEYemptyUsed for Ali and action.ai only together with S6S_PLATFORM_LLM_PROVIDER=openai.
S6S_ANTHROPIC_API_KEYemptyThe same, with S6S_PLATFORM_LLM_PROVIDER=anthropic.

Everything else on this page does not reach the container from .env, including S6S_TRUSTED_PROXY_HEADER, the worker tuning variables, and every OAUTH_<PROVIDER>_* pair except Google.

Passing other variables under Docker Compose

The stock file cannot pass them, so add your own override file next to docker-compose.yml. Compose merges docker-compose.override.yml automatically, and the ${…} values are still filled from .env. List only what you use:

docker-compose.override.yml
services:
  s6s:
    environment:
      S6S_TRUSTED_PROXY_HEADER: ${S6S_TRUSTED_PROXY_HEADER:-}
      OAUTH_SLACK_CLIENT_ID: ${OAUTH_SLACK_CLIENT_ID:-}
      OAUTH_SLACK_CLIENT_SECRET: ${OAUTH_SLACK_CLIENT_SECRET:-}

Run docker compose up -d again after changing either file.

Core

VariableRequiredDefaultDescription
DATABASE_URLYes(Compose: bundled database)PostgreSQL connection string. SUPABASE_DB_URL is accepted when it is unset. Under Compose it is fixed in docker-compose.yml; see Database for an external database.
S6S_CREDENTIAL_ENCRYPTION_KEYYes—AES-256-GCM key for stored credentials. Exactly 64 hex characters: generate with openssl rand -hex 32. Production will not start without a valid value. Keep a copy: credentials saved under one key cannot be read with another.
S6S_JWT_SECRETYes—Signs session tokens. Production will not start without it. Use a different random value from the encryption key (openssl rand -hex 32). Changing it signs everyone out.
S6S_BASE_URLProd(Compose: http://localhost:3000)Public URL of your instance. Webhook URLs, OAuth callbacks, and the links S6S returns or sends (deploy responses, credential connect links, notifications) are built from it. When it is unset, those links fall back to https://s6s.ai and OAuth callbacks use the request's own address. .env.example sets https://s6s.ai; change it.
S6S_LIVE_EXECUTIONNoDocker: true; unset: offMust be exactly true for integration steps (HTTP, Slack, Telegram, etc.) to call real services; otherwise they return mock output. action.ai, action.rag, action.mcp_tool, action.transform, action.code, action.filter and action.stop_and_error always run.
S6S_AUTH_DISABLEDNooffDevelopment only. Honoured only when NODE_ENV is not production (for example pnpm dev:web). A production server — the Docker image or next start — refuses to start when it is true. Unset means sign-in is required.
S6S_EDITIONNoImage: cloud; Compose: emptycloud or empty (community). See Community vs cloud edition.

Access and sign-in

VariableComposeDescription
S6S_PUBLIC_REGISTRATIONForwarded (default false)true opts in to open sign-up and satisfies the start-up check. It changes nothing else: sign-up is open to anyone whenever neither of the next two variables is set.
S6S_ALLOWED_EMAILSForwardedComma-separated list. Only these addresses can sign up or sign in, with a password or with Google/GitHub. It is checked at sign-in, so removing an address takes effect at that person's next sign-in, and API keys are not re-checked.
S6S_INVITE_CODEForwardedNew password sign-ups must enter this code. Google and GitHub sign-in then work only for an email that already has an account.
S6S_OPERATOR_EMAILSForwardedComma-separated. These addresses get the admin role when they sign in with Google or GitHub (a provider-verified address) on an account with no password. Needed in the cloud edition, where API keys and platform settings are admin-only; there the server only logs a warning when it is missing.
GOOGLE_CLIENT_ID / _SECRETForwardedGoogle sign-in. Both are required. Not the same variables as Google integrations (OAUTH_GOOGLE_*).
GITHUB_CLIENT_ID / _SECRETForwardedGitHub sign-in. Both are required.
S6S_ACCOUNT_EMAILS_ENABLEDNot forwardedSet to 1, together with S6S_ACCOUNT_EMAIL_FROM and RESEND_API_KEY, to enable password reset and email verification. Without all three, those routes answer 404 and the login page offers no password reset.

AI / LLM (chat builder + action.ai steps)

VariableComposeDescription
S6S_PLATFORM_LLM_PROVIDERForwardedopenai or anthropic. Selects the platform AI provider from the environment. Without it, the keys below are not used by Ali or action.ai.
S6S_PLATFORM_LLM_MODELForwardedOptional. Defaults to gpt-4o (OpenAI) or claude-sonnet-4-6 (Anthropic).
S6S_OPENAI_API_KEYForwardedKey used when the provider is openai. OPENAI_API_KEY is accepted instead (not forwarded by Compose).
S6S_ANTHROPIC_API_KEYForwardedKey used when the provider is anthropic. ANTHROPIC_API_KEY is accepted instead (not forwarded by Compose).

A key on its own does not turn on the chat builder or action.ai steps. Either set S6S_PLATFORM_LLM_PROVIDER as well, or choose a provider on the Settings page (see LLM keys). Under the stock Compose file, use the Settings page.

Network and proxy

VariableComposeDescription
S6S_TRUSTED_PROXY_HEADERNot forwardedThe one header your reverse proxy sets to the real client IP (for example x-real-ip on nginx, cf-connecting-ip on Cloudflare). When set, per-IP rate limits (sign-up, for example) use only that header. When unset, S6S takes the first of cf-connecting-ip, x-real-ip and x-forwarded-for, which a client that reaches port 3000 directly can fake.
S6S_ALLOW_PRIVATE_URLSNot forwardedLets outbound HTTP requests from workflow steps reach private and loopback addresses (10.x, 172.16–31.x, 192.168.x, 127.x) and cloud metadata hosts. Development only: a production server refuses to start when it is true, so production installs cannot call private-network addresses from workflows.

Container start (Docker image only)

VariableDefaultDescription
S6S_SEED_DEMO_WORKFLOWStrueSeed the demo workflows on every container start, re-enabling any you disabled. true or 1 turns it on.
S6S_WORKER_DAEMON_ENABLEDtrueStart the worker daemon in the same container as the web app. Set it to false only if you run the worker somewhere else.

Community vs cloud edition (S6S_EDITION)

Only the exact value cloud selects the cloud edition; anything else, including empty, is community. The Dockerfile sets S6S_EDITION=cloud and docker-compose.yml overrides it to empty, so Compose runs the community edition. A plain docker run of the image runs the cloud edition unless you pass -e S6S_EDITION=.

  • Community: AI Visibility pages and APIs are off (pages redirect to /dashboard, APIs answer 404 CLOUD_ONLY). Home is /dashboard. Every account (default role: editor) can manage API keys and platform settings, and Settings shows the AI provider card.
  • Cloud: AI Visibility pages and APIs are on, home is /visibility, and the worker also runs AI Visibility jobs. API keys and platform settings are admin-only (see S6S_OPERATOR_EMAILS), and Settings hides the AI provider card, so set the provider with S6S_PLATFORM_LLM_PROVIDER.

Integration learning (deploying recipe actions outside the built-in set) is not switched by S6S_EDITION. Its code lives in packages/cloud, which the Docker image builds and which has its own license (packages/cloud/LICENSE).

Credential Layers

S6S has four distinct credential layers. Understanding these is important for self-hosters.

1. Platform authentication (signing into S6S)

Users sign in with email and password, or with Google or GitHub when you configure them. Sign-in cannot be switched off in production: S6S_AUTH_DISABLED=true is honoured only in development mode, and a production server refuses to start with it. Who may sign up is controlled by the registration gate (S6S_ALLOWED_EMAILS, S6S_INVITE_CODE, or S6S_PUBLIC_REGISTRATION=true). Google and GitHub sign-in accept only an email address the provider has verified.

To enable Google sign-in, create an OAuth 2.0 Client ID in the Google Cloud Console, set GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET, and register this callback URL:

http://localhost:3000/api/auth/google/callback
# In production, use your S6S_BASE_URL:
https://workflows.mycompany.com/api/auth/google/callback

GitHub sign-in follows the same pattern — create an OAuth App in GitHub Developer Settings, set GITHUB_CLIENT_ID and GITHUB_CLIENT_SECRET, and use the callback URL {S6S_BASE_URL}/api/auth/github/callback.

2. Integration OAuth (connecting external services)

When a workflow needs to call Google Drive, Slack, YouTube, etc., users connect their accounts via OAuth. As a self-hoster, you need to create your own OAuth app for each service your users want to connect.

S6S uses a naming convention for integration OAuth env vars, and the callback URL for each app is {S6S_BASE_URL}/api/credentials/connect/<provider>/callback:

.env
# Google integrations (Drive, Sheets, Calendar, Gmail, YouTube)
OAUTH_GOOGLE_CLIENT_ID=<client id>
OAUTH_GOOGLE_CLIENT_SECRET=<client secret>

# Slack
OAUTH_SLACK_CLIENT_ID=<client id>
OAUTH_SLACK_CLIENT_SECRET=<client secret>

# General pattern:
# OAUTH_{PROVIDER}_CLIENT_ID=...
# OAUTH_{PROVIDER}_CLIENT_SECRET=...

OAuth providers: google, twitter, slack, github, notion, hubspot, microsoft, salesforce, quickbooks, dropbox, linkedin. The stock docker-compose.yml forwards only the Google pair; pass the others through an override file.

If a user tries to connect a provider that is not configured, S6S returns a clear error message indicating which environment variable to set.

Note: Google sign-in and Google integrations use separate variables — GOOGLE_CLIENT_* for sign-in, OAUTH_GOOGLE_CLIENT_* for connections. Both can point at the same Google OAuth client (register both callback URLs on it) or at two different clients. Make sure the client used for connections has the scopes your workflows need (Drive, YouTube, Sheets) enabled under "OAuth consent screen".

3. API key credentials (user-managed)

Many integrations (Buffer, Telegram, Notion, OpenAI, etc.) use API keys instead of OAuth. Users paste their own API keys into the S6S credentials page at /credentials, and S6S stores them encrypted with your S6S_CREDENTIAL_ENCRYPTION_KEY.

This requires no configuration from you as a self-hoster — it is entirely user-managed. When a workflow is deployed that needs credentials, the deploy response includes missing_credentials with a connect_url (built from S6S_BASE_URL) and setup instructions for each provider.

4. LLM keys (chat builder + action.ai)

S6S uses one platform-wide AI provider for two things: the chat workflow builder (Ali, the natural-language UI for creating workflows) and action.ai steps that make in-workflow LLM calls (e.g. summarize, classify, extract). Configure it in one of two ways:

  • Settings page (/settings, community edition): choose OpenAI, Anthropic, Google, OpenRouter, or a custom OpenAI-compatible endpoint, and paste the key. This works under the stock Compose file.
  • Environment: S6S_PLATFORM_LLM_PROVIDER plus the matching key (see the AI table above). When set, it takes precedence over the Settings value.

action.rag steps always use the provider saved in Settings, because they call an OpenAI-compatible embeddings endpoint. Deploying a recipe with actions outside the built-in set may also call the provider, to learn an integration S6S has not seen before.

Without a provider, workflows that use no action.ai or action.rag steps can still be deployed and executed via the API, SDK, or MCP. An action.ai step fails with AI_NO_LLM_CONFIGURED.

Cloud-only features: The AI Visibility Monitor is available exclusively on S6S Cloud. The self-hosted version includes the core workflow engine, all 32 node types, API, SDK, and MCP server.

Production Checklist

Before exposing S6S to the internet, work through this checklist:

S6S_CREDENTIAL_ENCRYPTION_KEY

64 hex characters from openssl rand -hex 32. The server will not start without it. Store a copy somewhere safe: without the same key, saved credentials cannot be decrypted.

S6S_JWT_SECRET

A second random value, different from the encryption key. The server will not start without it.

Registration gate

Prefer S6S_ALLOWED_EMAILS or S6S_INVITE_CODE over S6S_PUBLIC_REGISTRATION=true, which lets anyone who reaches the server sign up.

S6S_BASE_URL

Set to your public https:// URL (e.g. https://workflows.mycompany.com). Webhook URLs, OAuth callbacks and the links S6S returns are built from it.

Reverse proxy (TLS)

Put nginx, Caddy, or Traefik in front of S6S for HTTPS. S6S itself serves HTTP on port 3000. In production the session cookie is marked Secure, so sign-in needs HTTPS (localhost aside), and every response carries a two-year Strict-Transport-Security header with includeSubDomains.

S6S_TRUSTED_PROXY_HEADER

Set it to the client-IP header your proxy sets (e.g. x-real-ip), and keep port 3000 reachable only through the proxy, so per-IP rate limits see real client addresses.

Port 5432

Docker Compose publishes PostgreSQL on host port 5432 with the fixed password from docker-compose.yml. Block it from other machines.

S6S_LIVE_EXECUTION=true

Already the default in Docker. In a manual setup set it yourself (.env.example sets false); without it, integration steps return mock responses.

S6S_SEED_DEMO_WORKFLOWS=false

Optional. Stops the Docker image from re-seeding the demo workflows, and re-enabling them, on every start.

Back up pgdata volume

Schedule regular backups of the PostgreSQL data volume. All workflows, runs, and credentials live here.

Manual Setup (without Docker)

Prerequisites

  • Node.js 22+
  • pnpm 10+
  • PostgreSQL (the Docker setup uses 16; the migrations enable the pgcrypto extension)

Step-by-step

Terminal
# Clone and install
git clone https://github.com/Sawan6/S6S-ai.git
cd S6S-ai
pnpm install

# Configure environment
cp .env.example .env
# Edit .env:
#   DATABASE_URL                   your PostgreSQL connection string
#   S6S_CREDENTIAL_ENCRYPTION_KEY  output of: openssl rand -hex 32
#   S6S_JWT_SECRET                 a second, different: openssl rand -hex 32
#   S6S_BASE_URL                   your URL, e.g. http://localhost:3000
#   S6S_LIVE_EXECUTION             true, to call real services
#   Registration gate              uncomment S6S_ALLOWED_EMAILS,
#                                  S6S_INVITE_CODE or S6S_PUBLIC_REGISTRATION=true

# Build the packages (the migration and worker scripts import the compiled output)
pnpm build:pkg

# Run database migrations (this script does not read .env)
export DATABASE_URL="postgresql://user:password@localhost:5432/s6s"
npx tsx scripts/auto-migrate.ts

# Build the web app
pnpm build:web

# Seed demo workflows (optional)
pnpm db:seed

# Start the web app in production mode (port 3000)
pnpm --filter @s6s/web start

# In a separate terminal, start the worker daemon
pnpm worker:daemon

The web app loads the root .env (and .env.local), and the worker daemon and seed script load .env from the current directory, so run them from the repository root. The migration script reads only the shell environment, hence the export.

pnpm --filter @s6s/web start runs next start in production mode, so the same start-up checks as Docker apply: the two secrets above must replace the placeholders .env.example ships with.

pnpm dev:web starts development mode instead: the start-up checks are skipped and S6S_AUTH_DISABLED=true is honoured. It also stops whatever is listening on port 3000 first.

Both the web app and the worker daemon must be running for workflows to execute. In production, run them as separate processes or systemd services.

Worker Daemon

The worker daemon is the process that actually executes workflows. It uses PostgreSQL LISTEN/NOTIFY for instant wake-up when new runs are created, with adaptive polling (1s–10s) as fallback. It also checks cron schedules every 60 seconds and reaps stale runs.

The worker must be running for workflows to execute. In Docker it starts automatically inside the s6s container (unless S6S_WORKER_DAEMON_ENABLED=false). For manual setups, run it from the repository root as a separate process:

pnpm worker:daemon

Worker configuration

VariableDefaultDescription
S6S_WORKER_OWNERdaemon-mainWorker identity for run leasing. Use unique values when running multiple workers. (.env.example sets worker-main.)
S6S_WORKER_MAX_RUNS10Maximum runs processed per tick.
S6S_DAEMON_POLL_MIN_MS1000Minimum poll interval in milliseconds.
S6S_DAEMON_POLL_MAX_MS10000Maximum poll interval in milliseconds. The daemon adapts between min and max based on activity.
S6S_DAEMON_SCHEDULE_INTERVAL_MS60000How often to check for scheduled workflows (cron triggers).

The stock docker-compose.yml does not forward these, so the defaults apply under Docker Compose unless you add them to an override file.

Database

S6S requires PostgreSQL. Migrations live in packages/persistence/migrations/ and are applied by scripts/auto-migrate.ts, which records applied migrations in a _migrations table and applies only new ones.

Connecting to an external database

To use a managed PostgreSQL instance (e.g. Supabase, Neon, RDS) in a manual setup, set DATABASE_URL in .env (and export it before running migrations):

DATABASE_URL=postgresql://user:password@host:5432/s6s?sslmode=require

Under Docker Compose, DATABASE_URL is written into docker-compose.yml, so a value in .env does not change it. Set it for the s6s service in an override file instead; the bundled postgres container still starts.

Running migrations manually

# After pnpm build:pkg; this script does not read .env
export DATABASE_URL="postgresql://user:password@host:5432/s6s"
npx tsx scripts/auto-migrate.ts

In Docker, migrations run on every container start, before the server starts. If they fail, the container exits.

For a database that already has the S6S schema but no _migrations table, the script marks every migration as applied instead of running them. S6S_MIGRATION_BASELINE (all, or a comma-separated list of migration file names) records files as applied without running them; it is refused once any migration has been recorded.

Health Checks

S6S exposes a public /healthz endpoint for monitoring:

StatusHTTPMeaning
ok200The web app answered and its database queries succeeded.
degraded503A database query failed (for example, the database is unreachable). The body carries the error message.
Example
curl http://localhost:3000/healthz
# {"status":"ok","timestamp":"2026-10-06T12:00:00.000Z",
#  "runs":{"running":0,"succeeded":12,"failed":1,"cancelled":0},
#  "activeLeases":0}

# When a database query fails (HTTP 503):
# {"status":"degraded","error":"<database error message>"}

runs counts runs by status, and activeLeases counts running runs currently held by a worker. The endpoint does not check that the worker daemon is up: a stopped worker still reports ok.

Use this endpoint for load balancer health checks and liveness probes. The stock docker-compose.yml already uses it as the s6s service healthcheck; the Dockerfile itself defines no HEALTHCHECK.

Upgrading

To upgrade to the latest version:

Docker Compose
git pull
docker compose build
docker compose up -d

Migrations run automatically on startup. Demo seeding also runs on every start: it does not duplicate demo workflows, but it re-enables any you disabled unless S6S_SEED_DEMO_WORKFLOWS=false.

Manual setup
git pull
pnpm install
pnpm build:pkg            # build first: migrations run the compiled code
export DATABASE_URL="postgresql://user:password@host:5432/s6s"
npx tsx scripts/auto-migrate.ts
pnpm build:web
# Restart the web app and the worker daemon

MCP Server for Self-Hosted Instances

The S6S MCP server lets AI agents (Claude Desktop, Claude Code, Cursor, etc.) deploy and manage workflows. To point it at your self-hosted instance, set S6S_BASE_URL in the MCP config, and create the API key on your instance's /keys page (admin-only in the cloud edition):

Claude Desktop / Claude Code / Cursor — MCP config
{
  "mcpServers": {
    "s6s": {
      "command": "npx",
      "args": ["@s6s/mcp-server"],
      "env": {
        "S6S_API_KEY": "s6s_your_key_here",
        "S6S_BASE_URL": "https://workflows.mycompany.com"
      }
    }
  }
}

Replace https://workflows.mycompany.com with your actual S6S_BASE_URL. The MCP server defaults to https://s6s.ai if not set.

Next Steps

Need help?

Self-hosting is by arrangement during the private beta. Contact us for repository access and help.

The engine's early release notes are in the engine changelog.