OnceWise Flow

Self-hosting the sync server

Run oncewise-ai-sync — from a one-command dev setup to the published container image, environment variables, and the Herald sign-in gate.

The sync backend (oncewise-ai-sync) is a Rust/Axum service over PostgreSQL. It stores and distributes structured script data for spaces and never generates or executes flows. The server keeps no accounts, member tables or user profiles of its own: key spaces have no ownership, and on a gated deployment (below) the membership and roles of org-bound spaces live in the Herald organization layer, with the server storing only the space-to-organization link.

Quick run from source

For trying things out or developing:

docker run -d --name oncewise-demo-pg -e POSTGRES_PASSWORD=postgres -p 127.0.0.1:5432:5432 postgres:18-alpine

cd backend
DATABASE_URL=postgres://postgres:postgres@127.0.0.1:5432/postgres AUTH_MODE=none cargo run

The server listens on 0.0.0.0:8080 by default and runs database migrations at startup. Verify with:

curl http://127.0.0.1:8080/api/health        # → 200
curl http://127.0.0.1:8080/api/openapi.json  # the OpenAPI 3 document

AUTH_MODE=none is used above because the default mode requires Herald configuration (below). For anything reachable beyond your machine, do not ship none.

Container image

Every v*.*.* tag publishes an image:

docker pull ghcr.io/timzaak/oncewise:latest
docker run -d --name oncewise-sync \
  -e DATABASE_URL=postgres://user:pass@db:5432/oncewise \
  -e AUTH_MODE=none \
  -p 8080:8080 \
  ghcr.io/timzaak/oncewise:latest

Point the extension's Sync tab at the server's origin (for example https://sync.example.com) and you are done on the client side.

Environment variables

VariableDefaultRequiredNotes
DATABASE_URL—yespostgres://user:pass@host:5432/dbname
BIND_ADDR0.0.0.0:8080noListen address
AUTH_MODEheraldnoherald or none
HERALD_BASE_URL—when heraldHTTPS origin (HTTP only on loopback), no path/query/fragment
HERALD_REALM_ID—when heraldThe deployment-level realm; must match the status response
HERALD_CLIENT_ID—when heraldOAuth client app id registered in Herald
HERALD_REDIRECT_URI—when heraldHTTPS URL whose path is exactly /api/auth/oauth/callback
HERALD_ORG_API_KEY—when heraldServer-to-server key for the org channel: an API key bound to the HERALD_CLIENT_ID client app, carrying a role with the orgs.view and orgs.manage policies (1–4096 chars)

Startup fails fast with the names (never the values) of whatever is missing or malformed, so a broken config is safe to paste into an issue. Prepare HERALD_ORG_API_KEY in the Herald console: reuse (or create) the client app named by HERALD_CLIENT_ID, issue an API key bound to that app, and assign the key a role carrying orgs.view and orgs.manage. The startup error prints these steps when the variable is missing.

The Herald sign-in gate

By default (AUTH_MODE=herald) the server puts its business endpoints behind a sign-in: clients obtain a bearer token through the server's OAuth flow against a Herald deployment (also open source; its image is ghcr.io/timzaak/herald). Health, the OpenAPI document and the auth endpoints stay public.

The sign-in identity also powers the workspace layer: spaces created on a gated deployment are org-bound — the creator is the owner, joining happens by one-time invite, and membership with roles is resolved live from Herald on every request, so a removal or demotion takes effect on that person's next access. Spaces that predate the upgrade keep the space-code model with unchanged semantics; nothing is migrated.

On the extension side this is the login card in the Sync tab: one authorization window, then silent renewal.

AUTH_MODE=none restores the space-key-only behavior explicitly: every space is key-addressed, and the workspace endpoints (invites, members, ownership) answer 404. Anyone who obtains a space code can then use your server's space endpoints against it, so treat none as a loopback/dev convenience, not a deployment posture. Setting Herald variables while AUTH_MODE=none is active logs that they are being ignored.

HTTP surface

Endpoints group into auth (sign-in mode probe, OAuth start/callback, token refresh), spaces, a workspace group (invite issue and redeem, member list, role change, removal and self-exit, ownership transfer — gated deployments only), scripts and ops (health, OpenAPI). Key-space requests authenticate with the X-Space-Key header; gated deployments also require the bearer token in front of it. Org-bound spaces send no space key at all — access is the bearer token plus membership and role, judged live from Herald. The full request/response schemas are rendered from the backend's utoipa annotations in the OpenAPI reference and served live at /api/openapi.json.

On this page