README.md

Quickstart

Install, configure, and run Randal from the repository README.

Randal

The local-first Operator and gateway for autonomous AI agent posses.

Point it at an agent. Give it a config. Let it ride.

License: MIT Built with Bun TypeScript v0.1.0


Randal gives your agent a home base: open the Randal Operator, chat with the agent, configure real capabilities, and watch status without stitching together logs, jobs, and status pages yourself.

Under the hood, Randal wraps OpenCode (or any agent CLI) in a persistent execution loop and gives it superpowers:

  • 🧠 Memory + DAG β€” Agents learn, remember, share context, explain graph paths, and audit jobs through Postgres + pgvector
  • ⏰ Scheduling β€” Heartbeats, cron jobs, and webhook triggers keep your agents alive
  • πŸ” Credentials β€” Scoped env-var filtering with explicit allowlists and sandbox enforcement
  • πŸ–₯️ Randal Operator β€” First-party Run / Configure / Observe app for chat, live controls, file-backed config, built-in connectors, job status, memory, scheduler, analytics, mesh, and voice status
  • 🀝 Posse Mode β€” Multiple agents with shared memory and coordinated teamwork
  • πŸŽ™οΈ Voice (optional, experimental) β€” LiveKit + Twilio + STT/TTS integration for browser voice sessions and phone calls when you configure the required media services
  • 🌐 Multi-Instance Mesh β€” Distributed orchestration with specialization-based routing across machines
  • πŸ“Š Self-Learning Analytics β€” Human annotation feedback loops, reliability scoring, and prompt tuning
  • πŸ”Œ Gateway + Custom Relays β€” HTTP session API and SSE stream for bringing your own chat, product, or collaboration surface
  • 🧩 Guided Connectors β€” Manifest-driven optional Tavily, Image, Video, and Notion connectors with Operator/CLI setup and local user secret storage
  • 🌍 Browser Automation β€” Chrome/Chromium control via CDP for web browsing, screenshots, and interaction
  • πŸ”„ Real-Time Streaming β€” Line-by-line agent output, tool use, progress, and status events over Server-Sent Events
  • 🧩 Skills System β€” Discoverable, indexable, cross-agent skill sharing with file watching
  • 🎨 Image & Video Generation β€” AI-powered image and video workflows available through the runtime tooling
  • πŸ‘· Runtime Worker Orchestration β€” Root jobs can launch isolated child workers with inherited memory scope, structured context packets, root-centric events, and rollup accounting

One agent is useful. A posse is unstoppable.


⚑ Quick Start

curl -fsSL https://raw.githubusercontent.com/Hassion-Studio/randal/main/install.sh | bash

One command. Installs Bun (if needed), clones the repo, builds tools (steer, drive), links the CLI, runs the setup wizard, and configures Postgres-backed persistence.

Or clone and set up manually:

git clone https://github.com/Hassion-Studio/randal && cd randal
bun install && bun link
randal init --full   # durable config + generated OpenCode runtime wiring
randal

randal init creates durable Randal config/persona artifacts. randal setup regenerates disposable OpenCode runtime wiring (opencode.json, MCP/connectors, skills, plugins, and symlinks) from those artifacts and is safe to rerun. Bare randal opens the interactive OpenCode terminal entrypoint with Randal's generated config. It schedules startup diagnostics/self-heal in the background instead of waiting on config freshness checks, connector secret scans, Postgres setup, or plugin install before the TUI appears. Use randal serve when you want the Operator and daemon.

For standalone OpenCode without randal serve, enable connectors in durable config, save secrets with randal connector secret set, run randal setup, then start a fresh randal session. Use randal diagnostics for persistent startup warnings and randal doctor --fix (or randal setup --config <path> from a durable checkout) if generated MCP paths, skills, or post-rebase runtime wiring look stale.

Open the Randal Operator at http://localhost:7600. Your agent is live.

The Operator is the first-class path:

  1. Run randal serve.
  2. Open the Operator.
  3. Chat with Randal, configure built-in capabilities, watch streamed events, inject context, stop active work, and inspect status in one app.
  4. If you want Randal inside another product, build a custom relay against the gateway session API.

Optional: Enable Voice

Voice is off until you configure it. The primary end-to-end path in this branch is PSTN voice on Railway with Twilio + LiveKit + Deepgram + ElevenLabs. Browser/admin voice is supported, but it is secondary and stays behind the normal authenticated HTTP admin surface.

For the first working PSTN path, you need:

  1. A LiveKit project or self-hosted LiveKit server
  2. A Deepgram key for STT
  3. An ElevenLabs key for TTS
  4. A dedicated Twilio subaccount with a phone number
  5. A public HTTPS/WebSocket base URL that Twilio can reach for Randal's /voice/* routes

Minimum env vars for PSTN voice:

LIVEKIT_URL=wss://your-project.livekit.cloud
LIVEKIT_API_KEY=...
LIVEKIT_API_SECRET=...
DEEPGRAM_API_KEY=...
ELEVENLABS_API_KEY=...
ELEVENLABS_VOICE_ID=...                # optional, falls back to a default voice
RANDAL_VOICE_PUBLIC_URL=https://voice.example.com
TWILIO_ACCOUNT_SID=...                 # only for phone calls
TWILIO_AUTH_TOKEN=...                  # only for phone calls
TWILIO_PHONE_NUMBER=+15551234567       # only for phone calls

Important deployment split:

  • Local .env is for local development only.
  • The Railway deploy workflow copies GitHub Actions secrets into Railway.
  • If you use .github/workflows/railway-deploy.yml, set the voice values as GitHub repository secrets, not just in your local .env.

Then add the optional voice channel and config block:

gateway:
  channels:
    - type: http
      port: 7600
      auth: "${RANDAL_API_TOKEN}"
      corsOrigin: "${RANDAL_CORS_ORIGIN}"
    - type: voice

voice:
  enabled: true
  livekit:
    url: "${LIVEKIT_URL}"
    apiKey: "${LIVEKIT_API_KEY}"
    apiSecret: "${LIVEKIT_API_SECRET}"
  stt:
    provider: deepgram
    apiKey: "${DEEPGRAM_API_KEY}"
  tts:
    provider: elevenlabs
    apiKey: "${ELEVENLABS_API_KEY}"
    voice: "${ELEVENLABS_VOICE_ID}"

Use docs/voice-video-guide.md for the full setup flow and docs/voice-deployment-split.md for the production hosting split.

For Railway + Twilio specifically, start with the checklist in docs/voice-video-guide.md#minimum-viable-pstn-voice-on-railway.


🎬 Ways to Run

πŸ’» Terminal β€” randal

Open the interactive OpenCode terminal experience using Randal's installed OpenCode runtime and generated MCP config.

randal

randal --help and randal --version remain Randal CLI global flags. Unknown commands remain Randal errors; they are not passed through to OpenCode.

Background startup diagnostics are written to .randal/diagnostics/startup.json for the current workspace, or to the configured Randal state directory when no workspace config is available. If diagnostics report that background repairs changed generated OpenCode config, restart Randal/OpenCode to apply them.

🩺 Diagnostics β€” randal diagnostics

Inspect persistent startup diagnostics without waiting on normal startup:

randal diagnostics
randal diagnostics --json
randal diagnostics --refresh

Missing connector secrets are reported with connector IDs, secret names, labels, and remediation commands such as randal connector secret set image OPENROUTER_API_KEY. Diagnostics are redacted and must not contain raw secret values, bearer tokens, signed URLs, raw environment values, or full database URLs.

🎯 One-Shot β€” randal run

Fire and forget. Run a single job locally, get the output, exit. No server, no persistence. Perfect for quick tasks.

randal run "refactor the auth module"
randal run spec.md --model claude-sonnet-4

πŸ—οΈ Daemon β€” randal serve

Long-lived gateway with the Randal Operator, HTTP API, SSE event stream, job persistence, memory integration, and operational status. This is the control tower for your agent operations.

randal serve
randal serve --port 8080

randal serve starts the gateway without blocking on local OpenCode install checks or expensive startup self-heal. Non-critical diagnostics continue in the background and are visible through randal diagnostics.

For hosted or container deployments, do not use fallback HTTP credentials. Set RANDAL_API_TOKEN, set RANDAL_CORS_ORIGIN to the exact trusted browser origin, and constrain runner.allowedWorkdirs to the mounted workspace so authenticated callers cannot select arbitrary filesystem paths. Query-string bearer auth (?token=) is disabled by default; use Authorization: Bearer ... or /auth/session cookies instead.

Optional published-artifact bootstrap for runtime startup:

export RANDAL_MANAGED_CONTROL_PLANE_URL=https://control-plane.example
export RANDAL_MANAGED_WORKSPACE_ID=workspace-123
export RANDAL_MANAGED_VERSION_ID=version-7   # optional
randal serve

That path stays opt-in. By default, randal serve still starts from your local randal.config.yaml. When bootstrap metadata is enabled, runtime startup fetches the published artifact only and /instance surfaces runtime.mode=managed as runtime metadata.

See also:

  • docs/connectors.md
  • docs/config-studio.md
  • docs/architecture.md
  • docs/config-reference.md

Submit jobs remotely:

randal send "implement the payment webhook handler"
randal send feature-spec.md --agent opencode

Runtime worker orchestration stays root-job-centric for operators:

  • GET /jobs returns root jobs by default, with additive workerRollup fields when child workers ran.
  • GET /job/:id includes the root job plus any cost.childBreakdowns, lineage, backend, model, and cumulative child time data.
  • Relay/channel completions still route on the root job, with concise worker totals appended only when child workers were involved.

See docs/runtime-worker-orchestration.md for the runtime model, context packet format, recovery behavior, and backend extension points.

πŸ”Œ Custom Relay β€” Bring Your Own Surface

Want Randal in a chat product, support tool, internal portal, or incident room? Keep that product-specific code outside Randal and relay through the gateway:

# Create or reuse a session
curl -X POST http://localhost:7600/api/sessions \
  -H "Authorization: Bearer $RANDAL_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"title":"incident triage","threadId":"external-thread-42"}'

# Send a message into that session
curl -X POST http://localhost:7600/api/sessions/external-thread-42/messages \
  -H "Authorization: Bearer $RANDAL_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"content":"Find the root cause of the checkout errors."}'

# Stream session-scoped events back to your product
curl -N http://localhost:7600/api/sessions/external-thread-42/events \
  -H "Authorization: Bearer $RANDAL_API_TOKEN"

Use docs/channel-adapters-guide.md for the custom relay pattern and builder prompt.

πŸ€– Autonomous β€” Heartbeat + Cron + Hooks

This is where it gets interesting. The scheduler turns Randal from a job executor into a self-directed autonomous agent:

PrimitiveWhat It Does
πŸ’“ HeartbeatPeriodic wake-ups. Agent reads a checklist, decides what needs attention.
πŸ“… CronPrecise scheduled tasks. "At 7am, compile a morning briefing."
πŸͺ HooksExternal triggers via webhooks. CI pipelines, email watchers, alerts.
heartbeat:
  enabled: true
  every: 30m
  prompt: ./HEARTBEAT.md
  activeHours:
    start: "08:00"
    end: "22:00"

cron:
  jobs:
    morning-briefing:
      schedule: "0 8 * * *"
      prompt: "Review pending tasks. Compile a morning status."
      execution: isolated
      announce: true

hooks:
  enabled: true
  token: "${RANDAL_HOOK_TOKEN}"

🀝 Assemble Your Posse

A posse is a named group of Randal instances that coordinate as a team. Each agent has its own identity, persona, and specialization β€” but they share a brain.

# agent-a.config.yaml                    # agent-b.config.yaml
name: scout                              name: builder
identity:                                identity:
  persona: "You find and triage bugs."     persona: "You implement fixes."

memory:                                  memory:
  store: postgres                          store: postgres
  sharing:                                 sharing:
    publishTo: [posse-shared]                publishTo: [posse-shared]
    readFrom: [posse-shared]                 readFrom: [posse-shared]

Scout finds the problems. Builder fixes them. They share tenant-scoped memory, graph context, job timelines, and delegation audit through Postgres. No hand-off meetings required.

See examples/multi-agent-posse/ for a working two-agent setup.


πŸ› οΈ Configuration

Randal is configured via randal.config.yaml. All string values support ${ENV_VAR} substitution.

name: my-agent
runner:
  defaultAgent: opencode
  defaultModel: anthropic/claude-sonnet-4
  workdir: ~/dev/my-project

identity:
  persona: |
    You are a senior engineer who writes clean, tested code.
  rules:
    - "ALWAYS verify your work before marking complete"
    - "Write tests for new functionality"

credentials:
  envFile: ./.env
  allow: [ANTHROPIC_API_KEY]
  inherit: [PATH, HOME, SHELL, TERM]

Full reference: πŸ“– docs/config-reference.md


πŸ”Œ Custom Relays

The Console is built in. Custom relays are how you bring Randal to any other product without making that product an official adapter.

A relay owns external auth, users, threads, formatting, and retries. Randal owns sessions, jobs, events, memory, scheduling, and control actions. The seam is the gateway:

Relay NeedGateway Contract
Create or resume a conversationPOST /api/sessions
Send user text to RandalPOST /api/sessions/:id/messages
Stream output/progress/tools/status backGET /api/sessions/:id/events
Add context to active workPOST /api/sessions/:id/context
Stop active workPOST /api/sessions/:id/stop

Full pattern and reusable builder prompt: πŸ“– docs/channel-adapters-guide.md


πŸ’» CLI Reference

CommandDescription
randalπŸ’» Open the interactive OpenCode terminal entrypoint
randal initπŸ”§ Create durable config/persona artifacts (supports --wizard, --from, --yes, --full)
randal reset🧹 Clean slate β€” remove config and state (--all, --yes)
randal run <prompt|file>🎯 Run agent locally (one-shot)
randal serveπŸ—οΈ Start daemon (gateway + runner + scheduler)
randal send <prompt|file>πŸ“¨ Submit job to running instance
randal status [job-id]πŸ“Š Get job status
randal jobsπŸ“‹ List all jobs
randal stop <job-id>πŸ›‘ Stop a running job
randal context [job-id] <text>πŸ’‰ Inject context into running job
randal resume <job-id>πŸ”„ Resume a failed job
randal memory search|list|add🧠 Memory operations
randal message add|search|list|threadπŸ’¬ Message history management
randal skills list|search|show🧩 Skill management
randal cron list|add|removeπŸ“… Cron job management
randal heartbeat status|triggerπŸ’“ Heartbeat control
randal posse🀝 Multi-agent posse management
randal mesh status|route🌐 Mesh operations
randal analytics scores|recommendationsπŸ“Š Analytics and reliability
randal voice statusπŸŽ™οΈ Voice session management
randal gateway status|kill|restart|tokenπŸ—οΈ Gateway management
randal auditπŸ” Audit ambient host auth (SSH, GitHub, AWS, etc.)
randal setupπŸ”© Regenerate/sync generated OpenCode runtime wiring; idempotent
randal doctor [--fix]🩺 Validate or repair deployment, config, and local runtime wiring
randal update⬆️ Self-update (--check, --pin, --dry-run)
randal deploy agent|posse|env|list|deleteπŸš€ Railway deployment

Full reference: πŸ“– docs/cli-reference.md


πŸš€ Deploy Anywhere

curl -fsSL https://raw.githubusercontent.com/Hassion-Studio/randal/main/install.sh | bash

The installer handles Bun, dependencies, CLI registration, Postgres setup, and the setup wizard.

To start fresh: randal reset && randal init --full (or run interactive randal init and accept the recommended runtime setup offer).

See examples/local-mac/ for a full-featured local setup with heartbeat, cron, and active hours.

Local OpenCode-only is also supported: connector MCPs can run through launcher commands without randal serve; scheduler/heartbeat automation still requires randal serve or an authenticated gateway.

Deploy a single agent or a full multi-agent posse with the CLI:

# Single agent
railway login
randal deploy agent

# Multi-agent posse (shared Postgres + N agents)
randal deploy posse --name my-team

# Preview without deploying
randal deploy agent --dry-run

The official Docker image (ghcr.io/hassion-studio/randal:latest) bundles Bun, OpenCode, and Randal. Attach Postgres with DATABASE_URL/RANDAL_DATABASE_URL before treating memory, chat, jobs, mesh, and audit state as durable. Manage deployed posses with randal deploy list and randal deploy delete <name>.

See examples/cloud-railway/ for config examples and docs/deployment-guide.md for the full guide.

docker compose up --build

One command. Mount your config and point it at Postgres:

# docker-compose.yml is included at the repo root
# Just create randal.config.yaml and .env, then:
docker compose up --build

For the optional phone/media voice stack, start the dedicated overlay:

docker compose -f docker-compose.voice.yml up -d

This launches Redis, LiveKit, and the LiveKit SIP bridge for local voice testing. It does not start the Randal gateway itself. Run randal serve separately so the HTTP/WebSocket voice routes exist before you point Twilio or a public tunnel at them.


πŸ“¦ Programmatic Usage

Import @randal/harness to embed Randal in your own application. This is ideal for adding an AI agent to an existing project and deploying it alongside your own codebase.

import { createRandal } from "@randal/harness";

const agent = await createRandal({
  configPath: "./randal.config.yaml",
});

// Submit a job
await agent.runner.execute({
  prompt: "Refactor the auth module",
});

// Or let the heartbeat + cron handle things autonomously.
// The agent is now riding on its own. 🀠

// Clean shutdown
agent.stop();

Importing into an existing project

Extend the official Docker image with your config and files:

FROM ghcr.io/hassion-studio/randal:latest
COPY randal.config.yaml /app/randal.config.yaml
COPY knowledge/ /app/knowledge/

The image includes Bun, OpenCode, and Randal. Your Dockerfile controls what ships alongside it: codebase, knowledge files, and app data. Attach Postgres with a secret DATABASE_URL for durable memory/chat/job/mesh state. For custom pre-start logic, add a pre-start.sh that the entrypoint will source automatically.

See examples/imported-service/ for the full pattern and SECURITY.md for deployment mode guidance.


🧱 Architecture

                                         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                                         β”‚ πŸ–₯️ Randal Operatorβ”‚
                                         β”‚ run/config/observeβ”‚
                                         β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                                  β”‚ SSE / REST
                                                  β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  πŸ’» CLI  β”‚ ── HTTP ────────────────▢│                      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                          β”‚    πŸ—οΈ Gateway        β”‚
                                      β”‚                      β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                          β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚ Custom  β”‚ ── HTTP sessions/SSE ────▢│  β”‚  πŸ“‘ Gateway    β”‚  β”‚
β”‚ Relay   │◀──────────────────────────│  β”‚  - HTTP API    β”‚  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                          β”‚  β”‚  - Sessions    β”‚  β”‚
                                      β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
                                      β”‚          β”‚           β”‚
                                      β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
                                      β”‚  β”‚  πŸ”€ EventBus   β”‚  β”‚
                                      β”‚  β”‚  πŸ“‚ Job Persistβ”‚  β”‚
                                      β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
                                      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                                 β”‚
                                   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                                   β–Ό                           β–Ό
                          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                          β”‚    🎯 Runner     β”‚        β”‚   ⏰ Scheduler   β”‚
                          β”‚  - Brain Session β”‚        β”‚  - Heartbeat     β”‚
                          β”‚  - Adapters      β”‚        β”‚  - Cron          β”‚
                          β”‚  - Streaming     β”‚        β”‚  - Hooks         β”‚
                          β”‚  - Sentinel      β”‚        β”‚  (webhooks)      β”‚
                          β”‚  - Struggle Det. β”‚        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                          β”‚  - Browser (CDP) β”‚
                          β””β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”˜
                              β”‚          β”‚
                     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”˜          └────────┐
                     β–Ό                            β–Ό
               β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
               β”‚  πŸ” Credentials  β”‚      β”‚ 🧠 Memory + DAG  β”‚
               β”‚ - .env parsing   β”‚      β”‚ - Postgres       β”‚
               β”‚ - Allowlist      β”‚      β”‚ - Cross-agent    β”‚
               β”‚ - Services       β”‚      β”‚ - Auto-inject    β”‚
               β”‚ - Sandbox        β”‚      β”‚ - Posse sharing  β”‚
               β”‚ - Ambient audit  β”‚      β”‚ - Embeddings     β”‚
               β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β”‚ - Skills         β”‚
                                         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
        β”‚  🌐 Mesh         β”‚  β”‚  πŸ“Š Analytics    β”‚  β”‚  πŸŽ™οΈ Voice       β”‚
        β”‚ - Registry       β”‚  β”‚ - Annotations    β”‚  β”‚ - LiveKit        β”‚
        β”‚ - Discovery      β”‚  β”‚ - Reliability    β”‚  β”‚ - Twilio         β”‚
        β”‚ - Routing        β”‚  β”‚ - Feedback       β”‚  β”‚ - STT/TTS        β”‚
        β”‚ - Health         β”‚  β”‚ - Recommendationsβ”‚  β”‚  (experimental)  β”‚
        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

12 packages. Clean separation. See πŸ“– docs/architecture.md for the full breakdown.


πŸ“ Examples

ExampleWhat You Get
examples/minimal/🏁 Absolute minimum config β€” 2 fields, up and running
examples/local-mac/🍎 Full local macOS setup with heartbeat, cron, active hours
examples/cloud-railway/πŸš‚ Railway deployment with Dockerfile
examples/multi-agent-posse/🀝 Two agents sharing memory β€” the posse in action
examples/customer-support/🎧 Identity, knowledge base, cron jobs, webhook hooks
examples/imported-service/πŸ“¦ Import Randal as a dependency in your own app
examples/multi-instance-mesh/🌐 Multi-machine mesh with specialization-based routing
examples/full-platform/🏒 Full platform config with all features enabled
examples/voice-enabled/πŸŽ™οΈ Voice/video integration with LiveKit + Twilio
examples/browser-voice/πŸŽ™οΈ Browser-only voice with no Twilio dependency
examples/prompt-layers/πŸ“ Identity, knowledge, rules, and layered prompt composition
examples/analytics-driven/πŸ“Š Self-learning loop with annotation feedback

πŸ“‹ Prerequisites

RequirementNotes
Bun >= 1.1Runtime. Install
Agent CLIOpenCode (default adapter) or any compatible agent CLI
Postgres + pgvectorDurable memory, chat, graph/DAG, jobs, mesh, audit, and artifact metadata. Use randal db start locally or set DATABASE_URL.
Chromium (optional)For browser automation via CDP. Bundled in Docker image.
Python 3.11+ (optional)For drive terminal automation tool.
Swift (optional, macOS)For steer GUI automation tool.

πŸ“– Documentation

DocWhat's Inside
ArchitectureSystem design, package map, data flow diagrams
CLI ReferenceEvery command, every flag, HTTP API endpoints
Config ReferenceAll YAML config options with examples
Deployment GuideMac Mini, Railway, Docker, and Postgres setup
Postgres DAG OperationsLocal/cloud setup, migration, DAG concepts, dump/restore/copy, security, and runbooks
Custom Relay GuideGateway session API, SSE event loop, relay meta-code, builder prompt
Voice & Video GuideLiveKit, Twilio, STT/TTS integration
Mesh GuideMulti-instance deployment, routing, discovery
Browser Automation GuideCDP setup, screenshots, web interaction
Analytics GuideAnnotations, reliability scoring, feedback loops
Desktop Observer FoundationsObserver permissions, privacy, retention, and native/web boundaries
Security ModelDeployment modes, sandbox enforcement, isolation boundaries

Cutover Notes

This cleanup intentionally removes the legacy compaction and mixed loop-state model.

  • runner.compaction.* is no longer supported and now fails config validation.
  • .opencode/loop-state.json is the only canonical durable build-state surface, keyed by plan slug.
  • Runner-managed ad-hoc sessions no longer write job-ID keyed loop-state entries unless a canonical build key is explicitly supplied.
  • Legacy loop-state entries using old runner status values such as active, completed, or errored are treated as invalid and must be regenerated or cleaned up.
  • Gateway /instance now reports loop-state read errors explicitly instead of silently hiding corrupted state.

See docs/architecture.md and docs/config-reference.md for the final model.


MIT License · Built with 🀠 by the Randal posse

Saddle up.