This directory contains the production-oriented Docker setup for BrainDrive.
You can run installer commands from any of these directories:
- Repo root (e.g.
./scripts/install.sh localor./scripts/start.sh dev) - Installer root (e.g.
./installer/scripts/install.sh localor./installer/scripts/start.sh dev) - This directory (e.g.
./scripts/install.sh localor./scripts/start.sh dev)
For non-technical users, publish and use the bootstrap scripts from this repo:
installer/bootstrap/install.shinstaller/bootstrap/install.ps1installer/bootstrap/update.shinstaller/bootstrap/update.ps1
Recommended command examples:
- macOS/Linux:
curl -fsSL https://raw.githubusercontent.com/BrainDriveAI/BrainDrive/main/installer/bootstrap/install.sh | bash
- Windows PowerShell:
irm https://raw.githubusercontent.com/BrainDriveAI/BrainDrive/main/installer/bootstrap/install.ps1 | iex
Quick update commands:
- macOS/Linux:
curl -fsSL https://raw.githubusercontent.com/BrainDriveAI/BrainDrive/main/installer/bootstrap/update.sh | bash
- Windows PowerShell:
irm https://raw.githubusercontent.com/BrainDriveAI/BrainDrive/main/installer/bootstrap/update.ps1 | iex
Bootstrap behavior:
- Downloads installer files from GitHub (
codeloadtarball by default). - Installs or refreshes local installer files under
~/.braindrive/installer/docker. - Runs installer in
localmode by default (no domain required, pulls published images). prodis supported as an explicit mode override.
Optional bootstrap overrides:
BRAINDRIVE_BOOTSTRAP_REPO(default:BrainDriveAI/BrainDrive)BRAINDRIVE_BOOTSTRAP_REF(default:main, can be version tag)BRAINDRIVE_BOOTSTRAP_ARCHIVE_URL(full custom tarball URL)BRAINDRIVE_INSTALL_ROOT(default:~/.braindrive)BRAINDRIVE_BOOTSTRAP_FORCE_REFRESH=true(force re-download and refresh)
For a one-line, no-clone install that does not require DNS/TLS setup:
- macOS/Linux:
curl -fsSL https://raw.githubusercontent.com/BrainDriveAI/BrainDrive/main/installer/bootstrap/install.sh | bash
- Windows PowerShell:
irm https://raw.githubusercontent.com/BrainDriveAI/BrainDrive/main/installer/bootstrap/install.ps1 | iex
- Open:
http://127.0.0.1:8080
This mode uses prebuilt images and compose.local.yml.
Lifecycle scripts now always print the access URL and attempt a best-effort browser auto-open on the host.
For real public HTTPS deployments:
- macOS/Linux:
curl -fsSL https://raw.githubusercontent.com/BrainDriveAI/BrainDrive/main/installer/bootstrap/install.sh | bash -s -- prod
- Windows PowerShell:
$env:BRAINDRIVE_BOOTSTRAP_MODE='prod'; irm https://raw.githubusercontent.com/BrainDriveAI/BrainDrive/main/installer/bootstrap/install.ps1 | iex
- Set
DOMAINin~/.braindrive/installer/docker/.envbefore first production run.
- From repo root:
cp installer/docker/.env.example installer/docker/.env./scripts/install.sh(Linux/macOS/WSL) or./scripts/install.ps1(Windows)
- From
installer/:cp docker/.env.example docker/.env./scripts/install.shor./scripts/install.ps1
- From
installer/docker/:cp .env.example .env./scripts/install.shor./scripts/install.ps1
- Set
DOMAINandPAA_SECRETS_MASTER_KEY_B64ininstaller/docker/.env(script can auto-generate the key if missing). - Open
https://<DOMAIN>
install is first-run only. If .env already exists, install exits to avoid accidental account/secrets invalidation.
For local runs on prebuilt images (stable-style HTTP on localhost):
- Prepare
installer/docker/.env(as shown above). - Run local mode from any supported launch point:
- Repo root:
./scripts/install.sh local - Installer root:
./scripts/install.sh local - Docker installer dir:
./scripts/install.sh local
- Repo root:
- Open
http://127.0.0.1:8080(default bind). - Optional LAN access: set
BRAINDRIVE_LOCAL_BIND_HOST=0.0.0.0in.env, then restart/start local mode and openhttp://<this-machine-ip>:8080from another device on your network.
Local mode uses prebuilt images (same image/ref controls as local/prod) and does require registry pull access.
By default, first signup is allowed from any host/IP in this installer profile (PAA_AUTH_ALLOW_FIRST_SIGNUP_ANY_IP=true).
For day-to-day development with fast feedback loops:
- Prepare
installer/docker/.env(run install once if needed to generate secrets key). - Start dev mode:
- Repo root:
./scripts/start.sh dev - Installer root:
./scripts/start.sh dev - Docker installer dir:
./scripts/start.sh dev
- Repo root:
- Open
http://127.0.0.1:5073(default bind).
How dev mode works:
- Backend runs with
tsx watchagainst mounted source. - Web client runs Vite dev server with HMR.
- API calls proxy from Vite to backend (
/api-> app service). - Shared memory/secrets volumes are reused (
braindrive_memory,braindrive_secrets). - Startup update checks are not used in dev mode.
Optional LAN access for dev UI:
- Set
BRAINDRIVE_DEV_BIND_HOST=0.0.0.0in.env, restart dev mode, then openhttp://<this-machine-ip>:5073.
If file watching is unreliable (WSL/network mounts), enable polling in .env:
BRAINDRIVE_DEV_CHOKIDAR_POLLING=trueBRAINDRIVE_DEV_WATCHPACK_POLLING=true
compose.prod.yml: production stack (app + edge, TLS via Caddy).compose.local.yml: local stack (HTTP on${BRAINDRIVE_LOCAL_BIND_HOST:-127.0.0.1}:8080; set0.0.0.0for LAN access).compose.dev.yml: developer hot-reload stack (Vite UI on${BRAINDRIVE_DEV_BIND_HOST:-127.0.0.1}:${BRAINDRIVE_DEV_PORT:-5073})..env.example: required/optional runtime values.Caddyfile: production routing and TLS.Caddyfile.local: local HTTP routing.Dockerfile.app: production app image pipeline (gateway + MCP in one container).Dockerfile.edge: production edge image pipeline (static web assets + Caddy).entrypoint.sh: app startup orchestration for MCP + gateway.scripts/*: install, upgrade, backup, restore, and startup update-check helpers.
These Dockerfiles assume build context is repository root containing builds/ and installer/docker/.
Build and tag:
docker build -f installer/docker/Dockerfile.app -t ghcr.io/braindriveai/braindrive-app:v0.1.0 .
docker build -f installer/docker/Dockerfile.edge -t ghcr.io/braindriveai/braindrive-edge:v0.1.0 .Push:
docker push ghcr.io/braindriveai/braindrive-app:v0.1.0
docker push ghcr.io/braindriveai/braindrive-edge:v0.1.0Then set in .env:
BRAINDRIVE_TAG=v0.1.0- Optional platform override (local/prod image modes):
BRAINDRIVE_DOCKER_PLATFORM=linux/amd64
Optional (recommended for production): pin immutable image refs by digest in .env:
BRAINDRIVE_APP_REF=ghcr.io/braindriveai/braindrive-app@sha256:<digest>BRAINDRIVE_EDGE_REF=ghcr.io/braindriveai/braindrive-edge@sha256:<digest>
If you set one *_REF, set both.
When refs are set, compose uses them instead of BRAINDRIVE_*_IMAGE + BRAINDRIVE_TAG.
On Apple Silicon macOS, shell scripts automatically default local/prod image runs to
linux/amd64 when no explicit platform override is set.
Optional manifest-driven digest resolution (for upgrades):
BRAINDRIVE_RELEASE_MANIFEST=./release-cache/releases.jsonBRAINDRIVE_RELEASE_MANIFEST_SIG=./release-cache/releases.json.sigBRAINDRIVE_RELEASE_PUBLIC_KEY=./release-cache/cosign.pubBRAINDRIVE_RELEASE_MANIFEST_URL=https://github.com/BrainDriveAI/BrainDrive/releases/latest/download/releases.jsonBRAINDRIVE_RELEASE_MANIFEST_SIG_URL=https://github.com/BrainDriveAI/BrainDrive/releases/latest/download/releases.json.sigBRAINDRIVE_RELEASE_PUBLIC_KEY_URL=https://github.com/BrainDriveAI/BrainDrive/releases/latest/download/cosign.pubBRAINDRIVE_RELEASE_CHANNEL=stableBRAINDRIVE_RELEASE_VERSION=(optional explicit version override)BRAINDRIVE_REQUIRE_MANIFEST_SIGNATURE=trueBRAINDRIVE_AUTO_INSTALL_COSIGN=true(auto-download cosign if missing)BRAINDRIVE_COSIGN_VERSION=latest(optional version override)BRAINDRIVE_COSIGN_BIN_DIR=(optional install location override)BRAINDRIVE_COSIGN_BIN=(optional explicit cosign binary path)
If refs are not set and a manifest is configured, upgrade scripts resolve
BRAINDRIVE_APP_REF and BRAINDRIVE_EDGE_REF from the manifest.
If signature verification is required, upgrade scripts run cosign verify-blob before apply.
If cosign is missing, upgrade scripts now auto-install it by default (BRAINDRIVE_AUTO_INSTALL_COSIGN=true).
Current helper scripts use key-pair signature verification (trusted public key) without transparency log lookup.
Upgrade now auto-fetches metadata from configured release URLs into local release-cache so normal users do not need manual .env edits for each update.
Start in local/prod now runs startup update policy checks before compose up. Settings are resolved in this order: runtime env override, persistent /data/memory/system/config/app-config.json, .env, then defaults.
Lifecycle scripts that start/restart services (install, start, upgrade, restore) always print the URL and attempt browser auto-open; if auto-open fails, users can still use the printed URL.
- Start (local):
./scripts/start.sh local- Runs startup update check first (policy-driven), then starts containers.
- Stop (local):
./scripts/stop.sh local - Upgrade (local):
./scripts/upgrade.sh local - Start (developer hot reload):
./scripts/start.sh dev - Stop (developer hot reload):
./scripts/stop.sh dev - Upgrade (prod):
./scripts/upgrade.sh prod - Check update now (without start):
./scripts/check-update.sh local./scripts/check-update.sh prod
- Fetch remote metadata now (optional manual run, also done automatically in prod/local upgrade):
./scripts/fetch-release-metadata.sh
- Upgrade with explicit refs (one-shot, without editing
.env):BRAINDRIVE_APP_REF=ghcr.io/braindriveai/braindrive-app@sha256:<digest> BRAINDRIVE_EDGE_REF=ghcr.io/braindriveai/braindrive-edge@sha256:<digest> ./scripts/upgrade.sh
- Backup:
./scripts/backup.sh - Migration export (same method as app UI):
./scripts/migration-export.sh [output-file] [base-url] - Migration import (same method as app UI):
./scripts/migration-import.sh <archive-file> [base-url] - Migration smoke test (export + import roundtrip):
./scripts/migration-smoke.sh [dev|local|prod] [base-url] - Support bundle (logs + metadata + audit JSONL):
./scripts/support-bundle.sh [local|prod|dev] [24h] - Restore:
- Local:
./scripts/restore.sh memory <backup-file> local - Prod:
./scripts/restore.sh memory <backup-file> prod
- Local:
- Reset new-user test state (with confirmation):
./scripts/reset-new-user.sh- Add
--yesto skip prompt - Add
--fresh-cloneto also remove local.envand local images
- Add
- Windows equivalents:
- Start local:
./scripts/start.ps1 local- Runs startup update check first (policy-driven), then starts containers.
- Stop local:
./scripts/stop.ps1 local - Start developer hot reload:
./scripts/start.ps1 dev - Stop developer hot reload:
./scripts/stop.ps1 dev - Install:
./scripts/install.ps1 - Upgrade:
./scripts/upgrade.ps1 - Check update now:
./scripts/check-update.ps1 -Mode local./scripts/check-update.ps1 -Mode prod
- Fetch remote metadata now (optional manual run, also done automatically in prod/local upgrade):
./scripts/fetch-release-metadata.ps1- One-shot refs:
$env:BRAINDRIVE_APP_REF='ghcr.io/braindriveai/braindrive-app@sha256:<digest>'; $env:BRAINDRIVE_EDGE_REF='ghcr.io/braindriveai/braindrive-edge@sha256:<digest>'; ./scripts/upgrade.ps1
- Backup:
./scripts/backup.ps1 - Migration export (same method as app UI):
./scripts/migration-export.ps1 -Mode dev
- Migration import (same method as app UI):
./scripts/migration-import.ps1 -ArchiveFile <archive-file> -Mode dev
- Migration smoke test:
./scripts/migration-smoke.ps1 -Mode dev
- Support bundle (logs + metadata + audit JSONL):
./scripts/support-bundle.ps1 -Mode local -SinceWindow 24h
- Restore:
- Local:
./scripts/restore.ps1 -Target memory -BackupFile <backup-file> -Mode local - Prod:
./scripts/restore.ps1 -Target memory -BackupFile <backup-file> -Mode prod
- Local:
- Reset new-user state:
./scripts/reset-new-user.ps1(supports-Yesand-FreshClone)
- Start local:
Memory backup configuration is managed in the app UI:
- Open BrainDrive at
http://127.0.0.1:8080(or your production URL). - Open Settings -> Memory Backup.
- Set
Repository URLto an HTTPS git URL (example:https://github.com/<org>/<repo>.git). - Set
Git Token (PAT/Classic)and choose frequency:ManualAfter changesEvery hourEvery day
- Click
Save Backup Settings, then clickSave Nowto verify first push. - Confirm status fields in UI:
Last successful saveStatus(success/failed) and error message if present
Validation rules and safety:
- SSH remotes are intentionally unsupported for MVP (
git@.../ssh://...rejected). - Embedded credentials in URL are rejected (
https://user:pass@...). - Token is stored as vault secret reference; token plaintext is never returned in settings payload.
Restore from Backup Repo restores memory files only.
- Restores memory snapshot from fixed backup branch
braindrive-memory-backup. - Uses staging + rollback safety so partial apply is avoided on failure.
- Does not restore secrets from git backup.
- Does not change runtime/adapter config.
Use minimum required scope for pushes to your target repository:
- Private repository:
repo - Public repository only:
public_repo
Authentication failed for the backup repository- Verify PAT is valid and not expired.
- Verify PAT scope includes required repo write access.
- Verify the token owner has push permission to target repo.
Backup repository was not found or is not accessible- Confirm repository URL and visibility.
- Confirm token owner can access that repository.
Unable to reach the backup repository URL- Verify URL host/path, DNS, outbound network, and proxy/firewall settings.
Backup branch is not available in the configured repository(restore)- Run
Save Nowfirst to create/sync backup branch.
- Run
memory_backup.repository_url must use https://- Replace SSH URL with HTTPS URL.
For a complete local validation flow, see:
docs/onboarding/getting-started-testing-openrouter-docker.md
These are in installer/docker/scripts and intended for release operations.
- Build images:
./scripts/build-release-images.sh v0.1.0./scripts/build-release-images.ps1 -Version v0.1.0
- Push images and print digest refs:
./scripts/publish-release-images.sh v0.1.0./scripts/publish-release-images.ps1 -Version v0.1.0
- Generate
releases.jsonpayload:./scripts/generate-release-manifest.sh v0.1.0 <app-ref> <edge-ref> stable ./releases.json./scripts/generate-release-manifest.ps1 -Version v0.1.0 -AppRef <app-ref> -EdgeRef <edge-ref> -Channel stable -Output .\\releases.json
- Sign manifest (
releases.json.sig):./scripts/sign-release-manifest.sh ./releases.json ./releases.json.sig./scripts/sign-release-manifest.ps1 -ManifestPath .\\releases.json -SignaturePath .\\releases.json.sig
- Verify manifest signature:
./scripts/verify-release-manifest.sh ./releases.json ./releases.json.sig ./cosign.pub./scripts/verify-release-manifest.ps1 -ManifestPath .\\releases.json -SignaturePath .\\releases.json.sig -PublicKeyPath .\\cosign.pub
- Smoke test:
./scripts/smoke-test-release.sh https://<DOMAIN>./scripts/smoke-test-release.ps1 -BaseUrl https://<DOMAIN>
Cosign key setup (one-time per release signing identity):
- Generate key pair:
cosign generate-key-pair
- Keep
cosign.keyprivate in CI/secrets manager. - Distribute
cosign.pubas the trusted updater verification key. - For non-interactive signing (CI, no TTY), set
COSIGN_PASSWORDwhen using an encryptedcosign.key. - Shell release-sign/verify scripts support
BRAINDRIVE_COSIGN_BINand can auto-install cosign when missing (BRAINDRIVE_AUTO_INSTALL_COSIGN=true).
- Data is persisted in named volumes:
braindrive_memoryandbraindrive_secrets. - Structured audit logs are persisted to
memory/diagnostics/audit/YYYY-MM-DD(.N).jsonlwhile still emitting to stdout. - Audit retention/rotation env knobs:
PAA_AUDIT_FILE_SINK_ENABLED(defaulttrue)PAA_AUDIT_MAX_FILE_BYTES(default5242880)PAA_AUDIT_RETENTION_DAYS(default14)
- Support bundle API endpoints are enabled only in
auth_mode=local(JWT) and return403inlocal-ownermode:POST /api/support/bundlesGET /api/support/bundlesGET /api/support/bundles/:fileName
- Keep a secure backup of
PAA_SECRETS_MASTER_KEY_B64. Losing it may make encrypted secrets unreadable. - To enforce stricter first-account protection, set
PAA_AUTH_ALLOW_FIRST_SIGNUP_ANY_IP=falseand usePAA_AUTH_BOOTSTRAP_TOKEN.