airlock

package module
v0.4.0-rc.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 13, 2026 License: AGPL-3.0 Imports: 0 Imported by: 0

README

airlock

Airlock demo

Self-hosted platform for cyborg agents — programs that are half code, half AI. Fast and deterministic where they can be, AI-capable where they need to be.

Each agent runs as a long-lived Docker container with its own Postgres schema, S3 storage, web dashboard, custom HTTP routes ({slug}.your-domain.com), webhook ingress, cron scheduling, chat platform bridges (Telegram), and proxied access to LLMs and MCP tools. RBAC, real-time event streaming, full audit trail.

If "Heroku for cyborg agents, but I run it myself" lands, that's the shape.

[!WARNING] Alpha software. This is early-release code with bugs we haven't found yet. Self-hosting works today and we use it ourselves, but you'll likely hit edge cases nobody else has. Take regular Postgres backups, treat each release as "test it before relying on it," and please open an issue for anything that breaks.


Quickstart

Fastest: the installer

On a fresh Linux VPS (or macOS for local/tunnel), one command installs Docker, generates secrets, verifies your domain, wires TLS, and brings the stack up:

curl -fsSL https://raw.githubusercontent.com/airlockrun/airlock/v0.4.0-rc.1/install.sh | bash

Prefer to read it first (recommended for any curl | bash):

curl -fsSL https://raw.githubusercontent.com/airlockrun/airlock/v0.4.0-rc.1/install.sh -o install.sh
less install.sh && bash install.sh

It picks a deployment mode from what your host has:

  • Public server (public IP, ports 80/443) → on-demand Let's Encrypt TLS.
  • Public + Cloudflare → optional DNS-01 wildcard cert (one cert for all agent subdomains; no rate limit). The installer can also create the DNS records for you from the same token. Create it from the "Edit zone DNS" template (My Profile → API Tokens → Create Token), which grants exactly Zone → DNS → Edit + Zone → Zone → Read; scope it to your zone (e.g. example.com). (Not Zone:Edit, no account-level perms.)
  • No public IP (home/NAT/Mac) + Cloudflare → Cloudflare Tunnel: CF dials in and serves your domain with edge TLS, no open ports. Needs a tunnel token.
  • No domain → local mode (airlock.localhost, inline attachments).

Missing optional prereqs degrade gracefully (e.g. rootless BuildKit needs unprivileged user namespaces — on Ubuntu 23.10+ the installer offers to set the apparmor_restrict_unprivileged_userns sysctl; decline and it falls back to the legacy build). See docs/agent-isolation.md for the hardening knobs.

Re-run anytime; it's idempotent (--force to regenerate .env, --dry-run to preview, --local to force local mode).

Manual: 5 steps

If you'd rather wire it up yourself — a running self-hosted airlock instance.

Prerequisites:

  • Linux server with Docker 24+ and the Compose v2 plugin
  • A domain you control, with DNS administration access
  • Ports 80 and 443 reachable from the public internet
  • ~2 GB RAM, ~10 GB disk for a small install (more as agents and conversation history grow)
Don't have these set up yet? Click for install pointers.

Docker + Compose v2 — install per Docker's official guide (covers Ubuntu, Debian, RHEL, Fedora, etc.). Compose v2 ships as a plugin alongside Docker Engine since 2022; the install guide includes it. On a fresh Ubuntu/Debian server, the convenience script is the fastest path:

curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker $USER     # then log out/in so the group takes effect
docker compose version            # verify

Docker Desktop on macOS / Windows works for poking around but isn't suitable for a real self-host — you want a Linux server.

Firewall (ports 80 + 443) — on Ubuntu with UFW:

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw status

Cloud providers (DigitalOcean, Hetzner, AWS, GCP, etc.) usually have their own firewall layer in addition to the OS — check their dashboard/security-group settings for the same two ports.

Domain + wildcard DNS — at your DNS provider (Cloudflare, Namecheap, Route 53, etc.), add an A record where the name field is *.airlock (or * if airlock.example.com is the apex) and the value is your server's public IP. The wildcard covers per-agent subdomains like myagent.airlock.example.com automatically. Cloudflare has a walkthrough that maps cleanly to other providers' UIs.

Verify with dig +short anything.airlock.example.com once propagation completes (usually 1-5 min).

Steps:

# 1. Clone the repository and check out the latest release tag.
#    (Tracking `main` between releases is not supported — pin to a tag.)
git clone https://github.com/airlockrun/airlock
cd airlock
git checkout v0.4.0-rc.1

# 2. Generate secrets and edit configuration.
cp .env.example .env
# Edit .env:
#   - Set DOMAIN to your real domain (e.g. airlock.example.com)
#   - Generate ENCRYPTION_KEY: openssl rand -hex 32
#   - Generate JWT_SECRET:     openssl rand -hex 32

# 3. Add a wildcard DNS A record at your DNS provider:
#       *.your-domain.com  →  <your server IP>
#    Caddy will use this to issue TLS certs from Let's Encrypt.

# 4. Bring everything up. First launch pulls the four prebuilt images
#    (airlock, frontend, agent-builder, agent-base) from ghcr.io —
#    nothing builds locally. Subsequent launches are near-instant.
docker compose up -d

# 5. Get the first-run activation code, then sign in to create the admin user.
docker compose exec airlock cat /var/lib/airlock/activation_code.txt

Open https://your-domain.com in a browser, paste the activation code, set up the admin account.

The activation code is single-use and the file is removed after a successful activation.

Try it on your laptop

If you just want to kick the tires before standing up a real server:

cp .env.local.example .env
docker compose -f docker-compose.yml -f docker-compose.local.yml up -d
docker compose exec airlock cat /var/lib/airlock/activation_code.txt

Open https://airlock.localhost:24443, accept the browser warning on the first visit, paste the activation code. *.localhost resolves to 127.0.0.1 automatically (RFC 6761) in every modern browser, so per-agent subdomains route to your machine without any DNS or /etc/hosts work. The overlay binds Caddy on the rarely-used :24443 (HTTPS) and :24080 (HTTP) so it doesn't fight whatever you have on 80/443 — change HTTP_PORT / HTTPS_PORT (and the matching :port in PUBLIC_URL / S3_URL_PUBLIC) in .env if 24xxx is taken too. Caddy uses its built-in local CA so you don't need a real domain or Let's Encrypt; the file .env.local.example shows how to trust the CA permanently if you'd rather skip the warning.

This stack uses dummy secrets baked into the overlay — fine for poking around, not for anything you put real data into.

Develop against airlock from source

If you're hacking on airlock itself (Go backend, Vue frontend, agent build pipeline) and want fast iteration without rebuilding images on every save:

cp .env.dev.example .env
# Edit .env: set DOMAIN to suit your setup (airlock.localhost for laptop-only;
# 1.2.3.4.nip.io for a shared dev server reachable from other machines).
cd frontend && pnpm install && pnpm build && cd ..   # one-time, populates dist/
docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d
# In separate terminals:
go run ./cmd/airlock serve         # backend
cd frontend && pnpm watch          # vite build --watch — rebuilds dist/ on change

This overlay runs postgres + rustfs + caddy in containers and exposes the DB / S3 ports on 127.0.0.1 so the natively-running airlock binary can connect. The in-container airlock and frontend services are profile-disabled. Caddy serves the SPA from frontend/dist as static files and proxies API/WS traffic through host.docker.internal to your go run backend.

No vite dev server. Earlier versions of this overlay proxied to vite dev, but the dev server is a chronic CVE surface (HMR WebSocket file-read, /@fs/... filesystem access, etc.) — exposing it on a shared dev server with a real domain is asking for trouble. vite build --watch gives you the compiler without the server: edits trigger a sub-second rebuild, you refresh the browser manually. Worth it.

TLS modes (set in .env):

  • ACME_EMAIL unset (default): Caddy's local CA — works offline, browsers warn until you trust the CA.
  • ACME_EMAIL=you@example.com: real Let's Encrypt certs via on-demand HTTP-01, one per agent subdomain. Requires DOMAIN to resolve publicly and ports 80/443 reachable from the internet. Same shape as the prod self-host stack.

Updating

cd airlock
git fetch --tags
git checkout vX.Y.Z          # check the release notes for breaking changes first
docker compose up -d --build

Migrations run automatically on airlock startup. Always pg_dump before a major version bump if you care about your data.

What it does

  • Agent runtime — agents are user-written Go programs that import agentsdk. airlock builds them into Docker images and runs each as a long-lived container, reaped when idle.
  • Triggers — webhook ingress (POST /webhooks/{agent}/...), cron schedules, chat-platform bridges, custom HTTP routes on {slug}.your-domain.com.
  • LLM proxy — agents call LLMs through airlock, which injects credentials per-agent and (optionally) routes through telescope for inspection.
  • Storage — per-agent S3 prefixes (via RustFS) for files; per-agent Postgres schema for relational data.
  • Tools — built-in (HTTP, search, web fetch, file ops) plus MCP server integration.
  • Real-time — WebSocket stream of build events, tool calls, deltas; replay buffer for reconnects.
  • RBAC — tenant roles (admin / manager / user) and per-agent membership (admin / user / public).

Architecture

                                    ┌────────────────────┐
                                    │   Public traffic   │
                                    │  (browser, agent   │
                                    │   subdomains, etc) │
                                    └─────────┬──────────┘
                                              │ 80/443
                                  ┌───────────▼───────────┐
                                  │        Caddy          │  on-demand TLS,
                                  │ (TLS + reverse proxy) │  validated via
                                  └─┬─────┬───────────────┘  /caddy/ask
              ┌─────────────────────┘     │                    
              │                           │                    
   ┌──────────▼──────────┐    ┌───────────▼───────────┐    ┌──────────────────┐
   │      frontend       │    │       airlock         │◄───┤  Docker socket   │
   │  (Vue 3 SPA, Caddy) │    │   (Go API + chi +     │    │  (launches agent │
   └─────────────────────┘    │    WebSocket hub)     │    │   containers)    │
                              └─┬───────────┬─────────┘    └──────────────────┘
                                │           │
                       ┌────────▼─────┐  ┌──▼─────────┐
                       │   Postgres   │  │   RustFS   │
                       │ (per-agent   │  │ (per-agent │
                       │  schemas)    │  │  buckets)  │
                       └──────────────┘  └────────────┘

Agents launched by airlock join the same Docker network and reach airlock:8080, postgres:5432, rustfs:9000 by service name.

License

AGPL-3.0. The community edition is fully usable self-hosted; some operational features (e.g. SSO/OIDC, audit log export) are reserved for the commercial edition. No time-bombed trial.

A commercial license is available for those features and for organizations that can't ship AGPL software in their distribution. Contact hello@airlock.run.

Companion libraries are Apache-2.0:

Contributing

See CONTRIBUTING.md and CODE_OF_CONDUCT.md.

A CLA Assistant bot will prompt you to sign on your first PR — sign in with GitHub, click "I agree," done. The CLA covers all airlockrun open source projects (one signature, valid across repos).

Security

Reporting vulnerabilities: email security@airlock.run. Do not open a public issue.

What's protected by default:

  • AES-256-GCM at-rest encryption for provider API keys, OAuth tokens, webhook secrets (with rotation support).
  • Per-(email, ip) login throttling with constant-time response padding (closes both lockout-detection and email-enumeration timing channels).
  • TLS for all public traffic (Caddy, on-demand certs from Let's Encrypt).
  • JWT-scoped credentials per agent container; agents cannot access other agents' data.

Known gaps in v1 (planned, not done):

  • MFA is not implemented. A determined attacker rotating IPs can probe admin credentials without tripping the per-(email, ip) lockout. Mitigate with strong admin passwords and (recommended) putting airlock behind an edge proxy that does per-IP rate limiting (Cloudflare, fastly, your own nginx).
  • Per-IP rate limiting is intentionally not in airlock — your reverse proxy or CDN does this better. The Caddy in this compose handles TLS but not DDoS protection.
  • Email notifications on suspicious activity require SMTP, which the self-host doesn't bundle.

Project layout

airlock/                 this repo (AGPL-3.0)
  api/                   chi handlers, /api/v1, /api/agent, /webhooks, /health
  auth/                  JWT + RBAC + lockout
  builder/               agent build pipeline (scaffold → Sol codegen → docker build)
  container/             Docker container lifecycle
  db/                    Postgres + sqlc + goose migrations
  proto/airlock/v1/      shared protobuf definitions
  frontend/              Vue 3 dashboard (Vite + Pinia + PrimeVue)
  cmd/airlock/           binary entrypoint (subcommands: serve, auth)
  docker-compose.yml     this self-host stack
  Caddyfile              reverse proxy + TLS config
  Dockerfile.airlock     backend image
  Dockerfile.frontend    frontend SPA + serving Caddy
  Dockerfile.agent-base  base image for built agents
  Dockerfile.agent-builder  toolserver image with libs baked in

For deeper architecture (request flow, build pipeline, permission model, WebSocket envelope format), see CLAUDE.md (auto-loaded by Claude Code) or AGENTS.md (the same file under a tool-agnostic name).

Documentation

Index

Constants

View Source
const Version = "0.4.0-rc.1"

Version is the airlock release version. The release tag in git is "v"+Version (e.g. "v0.3.4"). Bumped manually before tagging; check-versions.sh enforces that this constant, the docker-compose.yml ghcr tags, and the README install step all agree.

Consumed at the module level so the default AGENT_BUILDER_IMAGE / AGENT_BASE_IMAGE in config tracks airlock's own version — drift between airlock and its matched toolserver/runtime images becomes a build-time error.

Variables

This section is empty.

Functions

This section is empty.

Types

This section is empty.

Directories

Path Synopsis
Package apihelpers carries the low-level HTTP/db utility functions shared by airlock's two HTTP surfaces:
Package apihelpers carries the low-level HTTP/db utility functions shared by airlock's two HTTP surfaces:
Package apitest is the integration test harness for the airlock API.
Package apitest is the integration test harness for the airlock API.
Package apperr holds the cross-cutting sentinel errors, their detail-wrapper, and the HTTP status mapping.
Package apperr holds the cross-cutting sentinel errors, their detail-wrapper, and the HTTP status mapping.
Package attachref resolves S3-backed attachment references (`s3ref:K`) emitted by agentsdk.attachToContext into storage-ready or LLM-ready forms.
Package attachref resolves S3-backed attachment references (`s3ref:K`) emitted by agentsdk.attachToContext into storage-ready or LLM-ready forms.
Package audio centralises audio-format conversion so every transcription entry point (bridge voice notes, agent-invoked /api/agent/llm/transcribe) normalises to a format every STT model accepts.
Package audio centralises audio-format conversion so every transcription entry point (bridge voice notes, agent-invoked /api/agent/llm/transcribe) normalises to a format every STT model accepts.
lockout
Package lockout implements per-(email, ip) login throttling for the airlock auth path.
Package lockout implements per-(email, ip) login throttling for the airlock auth path.
Package authz is the single authorization layer every surface gates through.
Package authz is the single authorization layer every surface gates through.
Package builder implements the agent build and upgrade pipeline.
Package builder implements the agent build and upgrade pipeline.
cmd
airlock command
airlockvet command
airlockvet runs the project-specific static checks for the airlock codebase.
airlockvet runs the project-specific static checks for the airlock codebase.
Package compat verifies that agent containers and this airlock process were built against compatible agentsdk versions.
Package compat verifies that agent containers and this airlock process were built against compatible agentsdk versions.
Package container provides container lifecycle management for agents.
Package container provides container lifecycle management for agents.
Package convert provides dbq→proto conversion functions shared by api and realtime packages.
Package convert provides dbq→proto conversion functions shared by api and realtime packages.
Package crypto provides AES-256-GCM encryption with versioned keys for rotation.
Package crypto provides AES-256-GCM encryption with versioned keys for rotation.
db
dbq
dbtest
Package dbtest provisions a database for integration tests.
Package dbtest provisions a database for integration tests.
migrations
Package migrations registers goose-driven schema and operational migrations.
Package migrations registers goose-driven schema and operational migrations.
Package execproxy implements the airlock-side SSH execution path for agentsdk.RegisterExecEndpoint.
Package execproxy implements the airlock-side SSH execution path for agentsdk.RegisterExecEndpoint.
gen
Package llmledger is the single writer for the llm_usage ledger — the authoritative record of every LLM token/cost charge in Airlock.
Package llmledger is the single writer for the llm_usage ledger — the authoritative record of every LLM token/cost charge in Airlock.
Package oauth provides OAuth 2.0 PKCE support for Airlock credential management.
Package oauth provides OAuth 2.0 PKCE support for Airlock credential management.
Package scaffold materializes agent project templates.
Package scaffold materializes agent project templates.
Package secrets provides a forward-compatible interface for secret storage.
Package secrets provides a forward-compatible interface for secret storage.
Package service holds the per-domain business-logic layer that sits between HTTP handlers and the database.
Package service holds the per-domain business-logic layer that sits between HTTP handlers and the database.
agents
Package agents owns the agent-lifecycle business logic: create, configure, build/upgrade/rollback, start/stop/suspend, list/get detail, and the per-agent git-remote bindings.
Package agents owns the agent-lifecycle business logic: create, configure, build/upgrade/rollback, start/stop/suspend, list/get detail, and the per-agent git-remote bindings.
bridges
Package bridges owns the chat-platform-integration lifecycle: create / list / update / delete a bridge row plus the corresponding poller goroutine and per-bridge driver state.
Package bridges owns the chat-platform-integration lifecycle: create / list / update / delete a bridge row plus the corresponding poller goroutine and per-bridge driver state.
catalog
Package catalog owns the read-only LLM catalog: providers + models (merged from models.dev with the hand-maintained overlay) + the per-provider capability matrix the Settings UI renders.
Package catalog owns the read-only LLM catalog: providers + models (merged from models.dev with the hand-maintained overlay) + the per-provider capability matrix the Settings UI renders.
connections
Package connections owns per-agent credential management: connections (API key / OAuth), MCP servers, env vars, and the aggregate setup-status signal.
Package connections owns per-agent credential management: connections (API key / OAuth), MCP servers, env vars, and the aggregate setup-status signal.
conversations
Package conversations owns the read/list/delete + topic-subscription lifecycle of web conversation threads.
Package conversations owns the read/list/delete + topic-subscription lifecycle of web conversation threads.
execendpoints
Package execendpoints owns the operator-facing CRUD + test of per-agent SSH exec endpoints (declared by the agent via RegisterExecEndpoint, configured by the operator here).
Package execendpoints owns the operator-facing CRUD + test of per-agent SSH exec endpoints (declared by the agent via RegisterExecEndpoint, configured by the operator here).
gitcredentials
Package gitcredentials owns the per-user git PAT credential surface (list / create / delete).
Package gitcredentials owns the per-user git PAT credential surface (list / create / delete).
identity
Package identity owns the per-user mapping from airlock users to external chat-platform user IDs (telegram / discord).
Package identity owns the per-user mapping from airlock users to external chat-platform user IDs (telegram / discord).
managedbots
Package managedbots owns the Telegram Bot API 9.6 "Managed Bots" create-flow's session correlation: airlock UI button → manager-bot deep link → user creates a bot in Telegram → manager-bot poller receives ManagedBotCreated → bridge row inserted.
Package managedbots owns the Telegram Bot API 9.6 "Managed Bots" create-flow's session correlation: airlock UI button → manager-bot deep link → user creates a bot in Telegram → manager-bot poller receives ManagedBotCreated → bridge row inserted.
members
Package members owns add/list/remove of agent_members rows — the per-agent sharing list.
Package members owns add/list/remove of agent_members rows — the per-agent sharing list.
models
Package models owns the per-agent model configuration: the eight capability overrides (build/exec/stt/vision/tts/image_gen/embedding/ search), each a (provider FK, bare model name) pair, plus the declared model slots and their per-slot assignments.
Package models owns the per-agent model configuration: the eight capability overrides (build/exec/stt/vision/tts/image_gen/embedding/ search), each a (provider FK, bare model name) pair, plus the declared model slots and their per-slot assignments.
providers
Package providers owns the tenant-wide LLM provider catalog: rows in the providers table, their encrypted API keys, and the lifecycle (create / list / update / delete).
Package providers owns the tenant-wide LLM provider catalog: rows in the providers table, their encrypted API keys, and the lifecycle (create / list / update / delete).
runs
Package runs owns the list / get / log / cancel operations for the runs table.
Package runs owns the list / get / log / cancel operations for the runs table.
settings
Package settings owns the single-row system_settings table: the tenant-wide default (provider FK, bare model name) pairs the agent-create flow prefills from.
Package settings owns the single-row system_settings table: the tenant-wide default (provider FK, bare model name) pairs the agent-create flow prefills from.
siblings
Package siblings is the per-agent "address book" of other agents the editing user wants this agent's LLM to be able to reach via A2A MCP.
Package siblings is the per-agent "address book" of other agents the editing user wants this agent's LLM to be able to reach via A2A MCP.
users
Package users owns the tenant-wide user directory: reads (List / ListDetail / Get / Lookup) at TenantUserView, and admin mutators (Create / UpdateRole / Delete) at TenantUserManage.
Package users owns the tenant-wide user directory: reads (List / ListDetail / Get / Lookup) at TenantUserView, and admin mutators (Create / UpdateRole / Delete) at TenantUserManage.
Package sysagent is the in-airlock chat agent that lets operators manage agents, bridges, connections, members, A2A, runs, and (later) other tenant resources through tool calls.
Package sysagent is the in-airlock chat agent that lets operators manage agents, bridges, connections, members, A2A, runs, and (later) other tenant resources through tool calls.
Package trigger provides services that trigger agent containers in response to external events: webhooks, cron schedules, and channel messages.
Package trigger provides services that trigger agent containers in response to external events: webhooks, cron schedules, and channel messages.
tgwebapp
Package tgwebapp verifies Telegram Web App initData payloads.
Package tgwebapp verifies Telegram Web App initData payloads.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL