🚀 Deployment Guide
Randal runs anywhere Bun runs. The core OSS deployment primitive is randal serve: one long-lived gateway/runner process, backed by your chosen persistence and exposed through whatever host or reverse proxy you prefer. This guide covers a local Mac Mini, a generic self-hosted/server model, Railway as one supported cloud example, and importing Randal as a library into an existing project.
The marketing/docs site is deployed separately as static Astro output on Vercel. See Public Site Deployment for Vercel previews, PostHog, domains, and public-site setup. That path is not required for self-hosting randal serve or deploying a cloud runtime.
📋 Prerequisites
All deployments require:
- Bun >= 1.1
- **OpenCode agent CLI installed and on PATH (
opencode) - Either provider API keys or a local OpenCode/OpenAI login you can bootstrap once with
opencode auth login - Postgres + pgvector for memory/search, chat, mesh, job audit, checkpoints, and annotations.
Optional connectors such as Tavily, Image, Video, and Notion are configured through Randal connector manifests and secret providers, not by editing generated OpenCode config. See Connectors and Secret Providers.
🍎 Mac Mini (Local)
A Mac Mini is the simplest deployment: Randal runs as a background process with launchd or a process manager.
1. Install
curl -fsSL https://raw.githubusercontent.com/Hassion-Studio/randal/main/install.sh | bash
This single command:
- Installs Bun (if not present)
- Clones the Randal repo to
~/randal - Installs dependencies and links the
randalCLI - Runs the interactive setup wizard
- Starts or validates local Postgres + pgvector for source-of-truth persistence
Or manually:
git clone <repo-url> ~/randal
cd ~/randal
bun install && bun link
randal init
randal setup
2. Configure
cd ~/randal # use examples/local-mac/ as a starting point
cp .env.example .env
# Edit .env with your API keys
Example randal.config.yaml:
name: home-agent
runner:
defaultAgent: opencode
defaultModel: anthropic/claude-sonnet-4
workdir: ~/dev
credentials:
envFile: ./.env
allow: [ANTHROPIC_API_KEY]
gateway:
channels:
- type: http
port: 7600
auth: "${RANDAL_API_TOKEN}"
memory:
store: postgres
database:
profile: local
url: "${DATABASE_URL:-postgres://randal:randal@127.0.0.1:5432/randal}"
ssl: disable
3. Postgres
Postgres is the source of truth for new installs. Use randal db start, randal db migrate, and /health to verify readiness before serving traffic.
To manage manually:
randal db start
randal db migrate
randal db status
Existing deployments should back up Postgres and verify randal db status --write-check before switching traffic.
4. Start Randal
cd ~/randal
randal serve
Optional published-artifact bootstrap on any deployment target:
export RANDAL_MANAGED_CONTROL_PLANE_URL=https://control-plane.example
export RANDAL_MANAGED_WORKSPACE_ID=workspace-123
export RANDAL_MANAGED_VERSION_ID=version-7
randal serve
Failure modes:
- bootstrap endpoint unreachable: startup fails
- version export missing: startup fails with published-artifact lookup error
- malformed YAML export: startup fails before the runtime begins serving
If you do not set managed bootstrap env vars, startup remains local-first.
To run as a persistent background service, create a launchd plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.randal.agent</string>
<key>ProgramArguments</key>
<array>
<string>/Users/you/.bun/bin/bun</string>
<string>/Users/you/randal/packages/cli/src/index.ts</string>
<string>serve</string>
</array>
<key>WorkingDirectory</key>
<string>/Users/you/randal</string>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>StandardOutPath</key>
<string>/tmp/randal.out.log</string>
<key>StandardErrorPath</key>
<string>/tmp/randal.err.log</string>
</dict>
</plist>
cp com.randal.agent.plist ~/Library/LaunchAgents/
launchctl load ~/Library/LaunchAgents/com.randal.agent.plist
5. Verify
curl http://localhost:7600/health
# {"status":"ok","uptime":...,"version":"0.1.0"}
# Open Randal Console
open http://localhost:7600/
🧱 Generic Server / VPS / Container Host
Use this model for any provider that can run Bun or a container and expose an HTTP port.
- Install Randal and OpenCode.
- Provide
randal.config.yamland required environment variables through your host's normal secret mechanism. - Run
randal serveunder systemd, launchd, Docker, Nomad, Kubernetes, or another process manager. - Expose the configured HTTP port, usually
7600, behind TLS and authentication-aware routing. - Persist Postgres data for memory, chat, jobs, checkpoints, mesh, and audit timelines. Persist
~/.randalorRANDAL_STATE_DIRseparately for scheduler files, workspaces, generated config/cache, and local connector secrets.
Connector credentials should be managed through randal connector secret set or the Console. Local connector secrets are stored under ~/.randal/secrets/workspaces/ by default. Randal Cloud will use user/workspace-level connector secret storage rather than requiring each customer connector secret to be configured as a hosting-provider deployment variable.
Connector changes do not require a full randal serve process restart. The gateway reloads connector config for new brain sessions and interrupts active brain sessions when necessary so the next session can see updated tools.
🚂 Railway (Cloud)
Railway is one supported hosting example, not a requirement for OSS Randal. The default Railway deployment is one Randal service backed by Railway managed Postgres or another pgvector-compatible DATABASE_URL.
For voice on Railway, the intended first working path is PSTN/Twilio. Browser voice remains supported, but is secondary and stays behind authenticated HTTP admin routes.
For voice deployments, treat Railway as a public gateway unless you explicitly
put the service behind private networking or another authenticated edge. Only
/, /health, and /assets/* are intentionally public. Browser token
issuance (POST /api/voice/token) and voice status (GET /voice/status) stay
behind normal HTTP auth.
1. Project Structure
Create a deployment directory with:
my-deployment/
randal.config.yaml
Dockerfile
railway.toml
2. Dockerfile
FROM ghcr.io/hassion-studio/randal:latest
# Copy your config
COPY randal.config.yaml /app/randal.config.yaml
# Copy knowledge files (if any)
# COPY knowledge/ /app/knowledge/
The official image includes Bun, OpenCode, and Randal. Durable memory, chat, mesh, jobs, checkpoints, and audit state live in Postgres; run migrations before treating the service as ready.
3. Railway Configuration
In the Railway dashboard or the GitHub Actions deploy workflow:
- Create a new project.
- Add a custom service pointing to your repo.
- Set environment variables.
If you use .github/workflows/railway-deploy.yml, set these as GitHub Actions
repository secrets because the workflow copies secrets into Railway. Your local
.env is not copied into Railway by that workflow.
| Variable | Value |
|---|---|
OPENCODE_AUTH_JSON | Preferred for GPT Pro / OpenCode OAuth on Railway. Paste the contents of ~/.local/share/opencode/auth.json after a local opencode auth login. |
OPENROUTER_API_KEY | Optional alternative for OpenRouter-based model access; required when the Video connector is enabled through its default OpenRouter path. |
OPENAI_API_KEY | Optional alternative for direct OpenAI API billing. |
ANTHROPIC_API_KEY | Optional alternative for direct Anthropic API billing. |
DATABASE_URL or RANDAL_DATABASE_URL | Required managed Railway Postgres or compatible external Postgres URL with pgvector, pg_trgm, and pgcrypto. |
RANDAL_STATE_DIR | Durable filesystem state root for workspaces, auth/tool caches, scheduler files, connector overlays, and control-plane local state. Postgres remains the source of truth for jobs, memory, chat, mesh, checkpoints, and audit. |
RANDAL_API_TOKEN | A generated secret for API auth |
RANDAL_REQUIRE_MEMORY | Set to true for hosted Railway deployments so startup and /health fail closed when Postgres memory is unavailable. |
RANDAL_STATE_DIR | Set to /data/randal; mount a Railway volume there for workspace and auth/tool cache persistence. |
RANDAL_VOICE_PUBLIC_URL | Public HTTPS/WSS base URL for Randal's /voice/* routes |
TAVILY_API_KEY | Optional Tavily connector key when your private config maps secrets.processEnv.connectors.tavily.TAVILY_API_KEY. |
LIVEKIT_URL | LiveKit server URL |
LIVEKIT_API_KEY | LiveKit API key |
LIVEKIT_API_SECRET | LiveKit API secret |
DEEPGRAM_API_KEY | Deepgram STT key |
ELEVENLABS_API_KEY | ElevenLabs TTS key |
ELEVENLABS_VOICE_ID | ElevenLabs voice ID |
TWILIO_ACCOUNT_SID | Twilio account SID |
TWILIO_AUTH_TOKEN | Twilio auth token |
TWILIO_PHONE_NUMBER | Twilio phone number in E.164 |
- Mount a Railway volume at
/dataand setRANDAL_STATE_DIR=/data/randal. - Set the deploy config to use your Dockerfile.
Production GitHub App flow: let Railway deploy committed code from Git, but keep deployment-specific Randal config private. Store a complete private config in Railway as RANDAL_CONFIG_YAML, or mount/write a private config file and set RANDAL_CONFIG_PATH. Use examples/cloud-railway/randal.config.connectors.yaml as a safe template for Tavily/Image/Video connectors; it maps connector secret names to Railway service env var names and does not contain raw secret values.
Console-managed connector flow: deploy the baseline config, then enable connectors in Console. The official Docker entrypoint enables RANDAL_CONNECTOR_OVERLAY=true, so non-secret connector enable/settings state persists at $RANDAL_STATE_DIR/connectors/overlay.yaml and connector secrets persist separately through the configured SecretProvider. Remote MCP OAuth tokens for connectors such as Notion are owned by OpenCode and persist in $HOME/.local/share/opencode/mcp-auth.json, normally $RANDAL_STATE_DIR/home/.local/share/opencode/mcp-auth.json because the official entrypoint sets durable HOME=$RANDAL_STATE_DIR/home. Config-declared connectors in RANDAL_CONFIG_YAML or RANDAL_CONFIG_PATH remain authoritative over overlay entries with the same id.
The checked-in root randal.config.railway.yaml remains a generic fallback and should not enable optional connectors that require credentials. Use a private config override for production connector enablement so missing Railway variables fail closed instead of silently exposing half-configured tools.
Railway persistence checklist:
- Mount a Railway volume at
/databefore treating the service as production. - Set
RANDAL_STATE_DIR=/data/randaland keep every durable runtime path under that root unless you intentionally use a more specific persistent override. - Use
/data/randal/workspaceforrunner.workdirso resumed jobs can see files created before a redeploy. - Attach managed Postgres and set
DATABASE_URLorRANDAL_DATABASE_URL; this is the source of truth for memory, chat, graph, mesh, jobs, and audit state. - Keep durable
HOME, OpenCode auth/session state, remote MCP OAuth tokens (mcp-auth.json), and agent-installed tools on the same mounted volume through the official image defaults.
Durable state ownership:
| Surface | Railway path | Owner | Notes |
|---|---|---|---|
| Job workspace/cache | /data/randal/workspace | Runner/OpenCode process files | Workspace output and partial files remain available after redeploy. Durable job records/events/checkpoints/audit timelines are in Postgres. |
| Scheduler state | /data/randal/heartbeat-state.yaml, /data/randal/cron.yaml | Scheduler heartbeat and cron | Wake items, tick counters, cron status, and last-run metadata survive restarts. |
| Gateway metadata | /data/randal/gateway.pid | Gateway | Runtime metadata follows the same state root for predictable operations. |
| Managed/control-plane state | /data/randal/control-plane | Control-plane file persistence | RANDAL_CONTROL_PLANE_STATE_DIR can override this when needed. |
| Runner workspace | /data/randal/workspace | Runner/OpenCode jobs | Job artifacts and partial work remain available after redeploy. |
| OpenCode home/session state | /data/randal/home | Entrypoint, OpenCode, and runner auth materialization | Default OpenCode auth/session/cache paths live under durable HOME, including $HOME/.local/share/opencode/auth.json and remote MCP OAuth tokens in $HOME/.local/share/opencode/mcp-auth.json. |
| Agent-installed tools | /data/randal/tools/bin | Entrypoint and agent runtime | Prepended to PATH before /app/tools/bin for tools that must survive image replacement. |
Use randal db dump, randal db restore, and randal db scoped-copy for Postgres backups and moves.
Railway runtime paths should not point at /app for durable filesystem state. Use /data/randal/workspace for runner.workdir, keep scheduler/control-plane/cache state under RANDAL_STATE_DIR, and treat /app as image/runtime scratch. Job records, events, checkpoints, tool invocation summaries, artifact metadata, and audit timelines belong in Postgres.
The official container sets HOME=$RANDAL_STATE_DIR/home, so default OpenCode auth/session/cache paths such as $HOME/.local/share/opencode survive redeploys. This directory includes provider auth.json and remote MCP OAuth token storage such as mcp-auth.json. It also prepends $RANDAL_STATE_DIR/tools/bin to PATH before /app/tools/bin; use that state-root tools directory for agent-installed tools that must survive image replacement. /app/knowledge and /app/tools/bin are image/runtime scratch unless you deliberately bake files into the image or mount them yourself.
On SIGTERM, SIGINT, or a gateway restart, Randal enters a drain mode: health reports draining, new job/scheduler mutations return 503 gateway_draining, scheduler state is flushed, active Postgres job records are updated with shutdown metadata, and child agent processes get RANDAL_SHUTDOWN_GRACE_MS milliseconds to exit before startup recovery resumes persisted queued and running jobs. The recovery model is Postgres-first for job state/audit plus filesystem persistence for workspace output; it does not guarantee every agent can semantically checkpoint mid-token before Railway stops the container.
Startup diagnostics: every gateway boot logs the resolved state root and derived durable paths for heartbeat, cron, control-plane state, OpenCode home, tools, and workspace, plus redacted Postgres health. Railway-like environments warn when RANDAL_STATE_DIR is unset or a durable surface points under known ephemeral roots such as /app or /tmp. Set RANDAL_STRICT_PERSISTENCE=true to escalate those warnings to error diagnostics during startup validation.
Extension points: keep filesystem-backed runtime state under RANDAL_STATE_DIR unless a backend owns that surface explicitly. Postgres owns jobs, memory, chat, mesh registry, checkpoints, annotations, delegation audit, and graph source-of-truth rows; Randal Cloud control-plane storage can replace individual non-source filesystem surfaces later without changing the Railway volume contract for workspaces/cache.
Use a dedicated Twilio subaccount for this deployment. The current PSTN runtime
expects TWILIO_ACCOUNT_SID + TWILIO_AUTH_TOKEN + TWILIO_PHONE_NUMBER, not
Twilio API keys.
4. Preferred GPT Pro / OpenCode OAuth Flow
This is the shortest path if you want Railway to run through an existing OpenCode login instead of API billing.
- Bootstrap locally once:
opencode auth login
- Confirm the local auth file exists:
ls ~/.local/share/opencode/auth.json
- Copy the file contents into the Railway secret named
OPENCODE_AUTH_JSON. - Deploy with
runner.opencodeAuth.mode: openai-oauth,runner.opencodeAuth.authFileEnv: OPENCODE_AUTH_JSON,runner.defaultModel: openai/gpt-5.4, andrunner.opencode.variant: xhigh.
Concrete Railway config:
name: my-cloud-agent
runner:
defaultAgent: opencode
defaultModel: openai/gpt-5.4
workdir: /data/randal/workspace
opencodeAuth:
mode: openai-oauth
authFileEnv: OPENCODE_AUTH_JSON
opencode:
variant: xhigh
credentials:
envFile: ./.env
allow: [OPENCODE_AUTH_JSON, OPENROUTER_API_KEY, OPENAI_API_KEY, ANTHROPIC_API_KEY, RANDAL_API_TOKEN, DATABASE_URL, RANDAL_REQUIRE_MEMORY, RANDAL_STATE_DIR, RANDAL_HOME_DIR, RANDAL_TOOLS_DIR, RANDAL_WORKSPACE_DIR]
inherit: [PATH, HOME, USER, SHELL, TERM, OPENCODE_AUTH_JSON, OPENROUTER_API_KEY, OPENAI_API_KEY, ANTHROPIC_API_KEY, DATABASE_URL, RANDAL_REQUIRE_MEMORY, RANDAL_STATE_DIR, RANDAL_HOME_DIR, RANDAL_TOOLS_DIR, RANDAL_WORKSPACE_DIR]
gateway:
channels:
- type: http
port: 7600
auth: "${RANDAL_API_TOKEN}"
memory:
store: postgres
index: memory-cloud-agent
database:
profile: generic
url: "${DATABASE_URL}"
ssl: require
migrationMode: validate-only
Operational caveat: the initial OpenAI/OpenCode login is local and interactive, but steady-state Railway runtime is headless after the secret is in place.
OpenCode persistence: OPENCODE_AUTH_JSON is materialized into $RANDAL_STATE_DIR/home/.local/share/opencode/auth.json because the container sets durable HOME before randal setup and randal serve. Remote MCP OAuth connectors use OpenCode's adjacent MCP auth store at $RANDAL_STATE_DIR/home/.local/share/opencode/mcp-auth.json. If a future OpenCode version requires additional adjacent session files, keep the full $RANDAL_STATE_DIR/home/.local/share/opencode directory on the same Railway volume rather than adding another service.
Security note: OPENCODE_AUTH_JSON is reusable session state. Store it only as a Railway secret, do not commit it, do not print it in logs, and rotate it by re-running opencode auth login if you suspect exposure.
API-based paths remain supported. If you prefer explicit provider billing instead of subscription auth, keep using OPENROUTER_API_KEY, OPENAI_API_KEY, or ANTHROPIC_API_KEY with the same Railway deployment flow.
5. Alternative API-Key Config for Railway
If you do not want to use the OAuth/session-based flow above, this API-key example remains supported:
name: my-cloud-agent
runner:
defaultAgent: opencode
defaultModel: anthropic/claude-sonnet-4
workdir: /data/randal/workspace
credentials:
envFile: ./.env
allow: [ANTHROPIC_API_KEY]
gateway:
channels:
- type: http
port: 7600
auth: "${RANDAL_API_TOKEN}"
memory:
store: postgres
index: memory-cloud-agent
database:
profile: generic
url: "${DATABASE_URL}"
ssl: require
migrationMode: validate-only
Note:
DATABASE_URLmust point at a migrated Postgres database. Runrandal db migrate --config randal.config.railway.yamlduring rollout, then let/healthvalidate Postgres reachability, migrations, extensions, and writeability.
Postgres Topology
For a normal single hosted Railway Randal, use one Randal service plus Railway managed Postgres. This is the first-class default: one Railway service, one DATABASE_URL, one Railway volume mounted at /data, and memory.store: postgres.
Use one shared Postgres database for a posse unless you intentionally isolate agents by database. Every agent still gets its own identity/scope while shared memory, graph, mesh registry, jobs, and audit events remain tenant/project-scoped rows.
Spawned runtime workers should not choose their own memory backend. They inherit the parent runtime's Postgres-backed memory/chat tools and tenant scope.
The GitHub Actions Railway workflow has an explicit topology input for manual dispatch:
single(default): deploys one Randal service using managed Postgres and/data/randalworkspace/auth persistence.posse: reserved for future multi-agent service creation. Current deployments should use managed Postgres for shared memory, graph, mesh registry, jobs, and delegation audit.
For direct CLI deployment of a Posse, generate per-agent configs with explicit name, posse, HTTP auth, mesh role/expertise, and a private mesh endpoint such as http://product-engineering.railway.internal:7600 so agents delegate over the Railway private network rather than registering localhost. Use Postgres-backed memory/mesh state for all deployments.
Persistence, Migration, And Backup
Railway deployments must attach managed Postgres and mount persistent storage at /data/randal. Postgres is the durable source of truth; agent workspaces and auth/tool caches live under /data/randal/workspace, /data/randal/home, and /data/randal/tools. Keep durable HOME on that volume so $HOME/.local/share/opencode/auth.json and remote MCP OAuth tokens in $HOME/.local/share/opencode/mcp-auth.json survive image replacement.
To migrate a hosted Randal to another computer, export the Randal config/secrets separately and use Postgres tooling for data. Use randal db dump/restore for whole-database or whole-schema moves, and randal db scoped-export/scoped-import/scoped-copy for one org/project without overwriting an entire cloud database. Dump and scoped manifests redact database URLs and report row counts/checksums.
Managed mode on Railway is optional. If you want the deployed runtime to start from the active published workspace artifact instead of a repo-local config file, provide:
| Variable | Value |
|---|---|
RANDAL_MANAGED_CONTROL_PLANE_URL | Control-plane base URL |
RANDAL_MANAGED_WORKSPACE_ID | Managed workspace ID |
RANDAL_MANAGED_VERSION_ID | Optional fixed version pin |
RANDAL_MANAGED_ARTIFACT_URL | Optional explicit export URL override |
RANDAL_CONTROL_PLANE_STATE_DIR | Optional explicit persistent directory for managed workspace state. If unset, it defaults to $RANDAL_STATE_DIR/control-plane. |
6. Deploy
# Via Railway CLI
railway up
# Or push to your connected Git repo for auto-deploy
git push origin main
Voice Deployment Guidance
Shared-instance voice is supported, but the safest production posture is split deployment:
- Admin/browser voice instance: private or tightly restricted, authenticated browser token issuance, full admin voice access.
- External/PSTN voice instance: public-facing, explicit external grants, no ambient admin trust unless intentionally configured.
Use one shared instance only if you accept the larger blast radius of putting a single gateway in front of both admin and external voice paths.
📦 Importing Randal into an Existing Project
You can add a Randal agent to an existing project by extending the official Docker image. This is ideal for adding an AI agent alongside your own codebase, knowledge base, or application.
How It Works
- Your Dockerfile extends
ghcr.io/hassion-studio/randal:latest(includes Bun, OpenCode, and Randal) - You copy your
randal.config.yamlinto the image - You ship whatever files your agent needs (codebase, knowledge, data)
- The official entrypoint handles
randal serve; configure Postgres withDATABASE_URL - For custom pre-start logic, add a
pre-start.shhook
1. Project Structure
your-project/
randal.config.yaml # agent configuration
Dockerfile # extends the official Randal image
knowledge/ # optional: files your agent needs
pre-start.sh # optional: custom startup logic
2. Dockerfile
FROM ghcr.io/hassion-studio/randal:latest
# Copy your config
COPY randal.config.yaml /app/randal.config.yaml
# Ship whatever your agent needs
COPY knowledge/ /app/knowledge/
# Optional: custom pre-start logic (e.g., DB sync)
# COPY pre-start.sh /app/pre-start.sh
The official image handles everything else — Randal serves on port 7600 and uses the configured Postgres database as its source of truth.
3. Pre-Start Hook
If you need custom logic before Randal starts (database sync, file setup, etc.), create a pre-start.sh. The Randal entrypoint sources this automatically:
#!/bin/bash
# pre-start.sh — runs before Randal starts
echo "Pulling data from my database..."
bun /app/scripts/sync-data.mjs || echo "Sync failed, continuing"
4. Security
The Docker container is the isolation boundary. Recommended config for imported usage:
sandbox:
enforcement: env-scrub
runner:
workdir: /data/randal/workspace
allowedWorkdirs:
- /data/randal/workspace
credentials:
allow: [ANTHROPIC_API_KEY] # only what the agent needs
See SECURITY.md for the full security model.
For imported-service Docker deployments, mount a persistent volume at /data or choose an equivalent host-backed path before using /data/randal/workspace for durable work. Keep /app for image contents and scratch files that can be replaced with the container.
5. Postgres Persistence
Set DATABASE_URL or RANDAL_DATABASE_URL for imported-service deployments before enabling memory, chat, mesh, job audit, or checkpoint recovery.
- Provision Postgres with
pgvector,pg_trgm, andpgcrypto. - Run
randal db migratebefore serving production traffic. - Set
memory.store: postgresin the Randal config.
6. Programmatic Usage (Advanced)
For full programmatic control, override the CMD to run your own entry point:
FROM ghcr.io/hassion-studio/randal:latest
COPY randal.config.yaml /app/randal.config.yaml
COPY index.ts /app/index.ts
CMD ["bun", "run", "/app/index.ts"]
import { createRandal } from "@randal/harness";
const randal = await createRandal({
configPath: "./randal.config.yaml",
});
See examples/imported-service/ for a complete working example.
🗄️ Postgres Setup
Postgres with pgvector is the durable source of truth for memory, chat, graph/DAG recall, mesh registry, jobs, checkpoints, annotations, and audit history.
📦 Local Install
randal db start
randal db migrate
randal db status --write-check
The local compose file uses pgvector/pgvector:pg16 and preserves the Docker volume between runs.
⚙️ Configuration
memory:
store: postgres
index: memory-my-agent
database:
profile: generic
url: "${DATABASE_URL:-postgres://randal:randal@127.0.0.1:5432/randal}"
ssl: disable
migrationMode: validate-only
For Railway and other managed providers, set ssl: require and provide DATABASE_URL or RANDAL_DATABASE_URL as a secret. Logs and manifests redact database credentials.
🤝 Cross-Agent Shared State
For multiple agents in a posse, use shared Postgres plus explicit tenant/project/instance identity. Agent-specific memory scopes and shared recall are represented as rows rather than separate search services.
🔒 Production Considerations
- Require
pgvector,pg_trgm, andpgcrypto. - Run migrations before serving production traffic.
- Set
RANDAL_REQUIRE_MEMORY=true;/healthreturns 503 if Postgres source-of-truth readiness fails. - Use
randal db dump/restorefor full database movement andrandal db scoped-export/scoped-import/scoped-copyfor project/org-scoped movement.
🔌 Custom Relay Setup
The Randal Console is built in. If you want Randal inside another product, deploy a small custom relay next to that product and connect it to the gateway session API.
Minimum relay environment:
RANDAL_GATEWAY_URL=https://your-randal-service.example
RANDAL_API_TOKEN=strong-token-from-randal-config
Minimum gateway config:
gateway:
channels:
- type: http
port: 7600
auth: "${RANDAL_API_TOKEN}"
Relay flow:
- Verify the external product webhook.
- Map the external thread ID to a Randal session ID.
- Call
POST /api/sessions. - Call
POST /api/sessions/:id/messagesfor inbound user text. - Subscribe to
GET /api/sessions/:id/eventsand render output back to the product.
See Custom Relay Guide for meta-code and the reusable builder prompt.
🔑 Environment Variables Reference
| Variable | Used By | Description |
|---|---|---|
RANDAL_API_TOKEN | 📡 Gateway HTTP auth | Bearer token for API authentication. |
DATABASE_URL / RANDAL_DATABASE_URL | 🧠 Postgres source-of-truth | Managed or local Postgres URL. Keep secret; Randal redacts it in diagnostics. |
RANDAL_REQUIRE_MEMORY | 🧠 Memory/health | Set to true for hosted deployments so startup and /health fail closed when Postgres is unavailable. |
RANDAL_STATE_DIR | 💾 Filesystem persistence | Persistent state root for Railway/Docker workspaces, caches, connector overlays, scheduler files, and control-plane local state. Postgres owns jobs, memory, chat, mesh, checkpoints, and audit rows. Recommended /data/randal. |
ANTHROPIC_API_KEY | 🤖 Agent (Claude/OpenCode) | Anthropic API key for model access. |
OPENROUTER_API_KEY | 🤖 Agent / Embedder | OpenRouter API key (if using OpenRouter models). |
OPENAI_API_KEY | 🔌 Embedder | OpenAI API key (if using OpenAI embeddings). |