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
.envfile. - 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.httpfor 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:
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_KEYis exactly 64 hex characters.S6S_JWT_SECRETis set. Use a second, different random value.- One registration gate is set:
S6S_PUBLIC_REGISTRATION=true,S6S_ALLOWED_EMAILS, orS6S_INVITE_CODE. The stockdocker-compose.ymlforwards all three (see what Compose forwards). S6S_AUTH_DISABLEDandS6S_ALLOW_PRIVATE_URLSare nottrue.- No secret contains placeholder text:
placeholder,changeme,change-me,replace, or a leadingyour-.
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 port5432with the fixed password written indocker-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=falseto 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
.envin the project folder only to fill the${…}placeholders indocker-compose.yml. A variable reaches the container only ifdocker-compose.ymllists it underenvironment:, and.envitself is excluded from the image. Any other variable you put in.envis silently ignored. - Manual setup: the web app and the worker read the root
.envdirectly; the migration script does not (see Manual Setup).
What the stock docker-compose.yml forwards
| Variable | When not set in .env | Description |
|---|---|---|
| DATABASE_URL | Fixed | The bundled postgres service. A value in .env does not change it. |
| NODE_ENV | production | Fixed. Turns on the start-up checks above. |
| S6S_LOG_FORMAT | json | Fixed. |
| S6S_CREDENTIAL_ENCRYPTION_KEY | empty | Required: the server will not start while it is empty. |
| S6S_JWT_SECRET | empty | Required: the server will not start while it is empty. |
| S6S_ALLOWED_EMAILS | empty | Registration gate: only these emails (comma-separated) may sign up or sign in. |
| S6S_INVITE_CODE | empty | Registration gate: new sign-ups need this code. |
| S6S_PUBLIC_REGISTRATION | false | Registration gate: true opens sign-up to anyone. One of the three gates must be set. |
| S6S_OPERATOR_EMAILS | empty | These emails get the admin role when they sign in with Google or GitHub (accounts without a password). |
| S6S_BASE_URL | http://localhost:3000 | Set your public URL in production. |
| S6S_LIVE_EXECUTION | true | Integration steps call real services. |
| S6S_AUTH_DISABLED | false | Must stay off in production. |
| S6S_SEED_DEMO_WORKFLOWS | true | Seed demo workflows on every start. |
| S6S_WORKER_DAEMON_ENABLED | true | Start the worker inside the container. |
| S6S_EDITION | empty | Community edition. |
| GOOGLE_CLIENT_ID / _SECRET | empty | Google sign-in. |
| GITHUB_CLIENT_ID / _SECRET | empty | GitHub sign-in. |
| OAUTH_GOOGLE_CLIENT_ID / _SECRET | empty | Google integration connections (Drive, Sheets, Gmail, YouTube). |
| S6S_PLATFORM_LLM_PROVIDER | empty | openai or anthropic: the AI provider for Ali and action.ai. Empty = the provider saved in Settings. |
| S6S_PLATFORM_LLM_MODEL | empty | Optional model for that provider. |
| S6S_OPENAI_API_KEY | empty | Used for Ali and action.ai only together with S6S_PLATFORM_LLM_PROVIDER=openai. |
| S6S_ANTHROPIC_API_KEY | empty | The 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:
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
| Variable | Required | Default | Description |
|---|---|---|---|
| DATABASE_URL | Yes | (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_KEY | Yes | — | 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_SECRET | Yes | — | 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_URL | Prod | (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_EXECUTION | No | Docker: true; unset: off | Must 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_DISABLED | No | off | Development 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_EDITION | No | Image: cloud; Compose: empty | cloud or empty (community). See Community vs cloud edition. |
Access and sign-in
| Variable | Compose | Description |
|---|---|---|
| S6S_PUBLIC_REGISTRATION | Forwarded (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_EMAILS | Forwarded | Comma-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_CODE | Forwarded | New 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_EMAILS | Forwarded | Comma-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 / _SECRET | Forwarded | Google sign-in. Both are required. Not the same variables as Google integrations (OAUTH_GOOGLE_*). |
| GITHUB_CLIENT_ID / _SECRET | Forwarded | GitHub sign-in. Both are required. |
| S6S_ACCOUNT_EMAILS_ENABLED | Not forwarded | Set 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)
| Variable | Compose | Description |
|---|---|---|
| S6S_PLATFORM_LLM_PROVIDER | Forwarded | openai 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_MODEL | Forwarded | Optional. Defaults to gpt-4o (OpenAI) or claude-sonnet-4-6 (Anthropic). |
| S6S_OPENAI_API_KEY | Forwarded | Key used when the provider is openai. OPENAI_API_KEY is accepted instead (not forwarded by Compose). |
| S6S_ANTHROPIC_API_KEY | Forwarded | Key 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
| Variable | Compose | Description |
|---|---|---|
| S6S_TRUSTED_PROXY_HEADER | Not forwarded | The 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_URLS | Not forwarded | Lets 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)
| Variable | Default | Description |
|---|---|---|
| S6S_SEED_DEMO_WORKFLOWS | true | Seed the demo workflows on every container start, re-enabling any you disabled. true or 1 turns it on. |
| S6S_WORKER_DAEMON_ENABLED | true | Start 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 404CLOUD_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 (seeS6S_OPERATOR_EMAILS), and Settings hides the AI provider card, so set the provider withS6S_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:
# 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_PROVIDERplus 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_KEY64 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_SECRETA second random value, different from the encryption key. The server will not start without it.
Registration gatePrefer S6S_ALLOWED_EMAILS or S6S_INVITE_CODE over S6S_PUBLIC_REGISTRATION=true, which lets anyone who reaches the server sign up.
S6S_BASE_URLSet 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_HEADERSet 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 5432Docker Compose publishes PostgreSQL on host port 5432 with the fixed password from docker-compose.yml. Block it from other machines.
S6S_LIVE_EXECUTION=trueAlready 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=falseOptional. Stops the Docker image from re-seeding the demo workflows, and re-enabling them, on every start.
Back up pgdata volumeSchedule 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
pgcryptoextension)
Step-by-step
# 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
| Variable | Default | Description |
|---|---|---|
| S6S_WORKER_OWNER | daemon-main | Worker identity for run leasing. Use unique values when running multiple workers. (.env.example sets worker-main.) |
| S6S_WORKER_MAX_RUNS | 10 | Maximum runs processed per tick. |
| S6S_DAEMON_POLL_MIN_MS | 1000 | Minimum poll interval in milliseconds. |
| S6S_DAEMON_POLL_MAX_MS | 10000 | Maximum poll interval in milliseconds. The daemon adapts between min and max based on activity. |
| S6S_DAEMON_SCHEDULE_INTERVAL_MS | 60000 | How 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:
| Status | HTTP | Meaning |
|---|---|---|
| ok | 200 | The web app answered and its database queries succeeded. |
| degraded | 503 | A database query failed (for example, the database is unreachable). The body carries the error message. |
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:
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.
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):
{
"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.