orbseal/Docs

Architecture

Orbseal models application configuration as a hierarchy of scopes. Values flow down from the broadest scope to the most specific, and the most specific one always wins.


The scope chain

Organization
  └── Workspace          (e.g. "acme-eu", "acme-us")
        └── Project       (e.g. "taskflow", "billing-api")
              └── Environment  (e.g. "production", "staging")
                    └── User   (individual overrides)

A single key such as taskflow:theme can have a value at any level. When a user requests their config, Orbseal resolves each key by walking from the most specific scope (user) up to the most general (workspace), returning the first value it finds.

Resolution order (most specific wins):
  user  →  environment  →  project  →  workspace  →  default

This lets you set sensible defaults at the workspace level (e.g. max_seats: 5) and let individual environments or users override specific keys without touching anything else.


Schema-first

Every key must be declared in orb.yaml before a value can be set. The schema defines:

  • typestring, number, boolean, enum, json, secret
  • scope — the narrowest scope where this key can be set
  • required — whether a release will fail if no value is found
  • overridable — whether users can override the value themselves
  • default — fallback if no value is explicitly set

Sync your schema with:

npx orbseal sync

Breaking changes (type change, scope narrowing) are blocked. Non-breaking updates (new default, label change) are applied automatically and increment the definition version.


Releases and snapshots

A release is a point-in-time snapshot of all resolved non-secret config for a specific environment. It is immutable — once created it never changes, even if you update values later.

POST /v1/workspaces/:ws/projects/:proj/environments/:env/release

Releases are identified by a monotonically increasing version number and an etag (first 8 bytes of a SHA-256 fingerprint of the config + version). Your app can cache the config as long as the etag matches, and only re-fetch when it changes.

etag: 9e691b38a0b25e68

Secrets are not included in snapshots. They are resolved live at runtime from sealed ciphertext, decrypted client-side by the app using its private key.


App keys

Your application authenticates with an app key (orb_live_...). Each app key is scoped to a project and optionally to a single environment. It carries the app's public key so Orbseal knows which ciphertext to return for secrets.

orb_live_9b6b5364b49174c8…

Admin operations (managing workspaces, setting values, creating releases) use admin tokens (orb_admin_...).


Data flow at runtime

App startup
  │
  ├─ GET /v1/config/resolve        ← app key token
  │    │
  │    ├─ config: { key: value }   ← plaintext, scope-resolved
  │    └─ secrets: { key: ciphertext }
  │
  └─ Decrypt secrets client-side
       using app private key (X25519 sealed-box)

The server never sees your private key or your secret values in plaintext.


Multi-tenancy

Workspaces map directly to tenants. Each workspace gets its own slug and short ID:

  • slug — human-readable, URL-safe, mutable: acme-eu
  • short_id — 6-character immutable identifier: xzvdrg

Both can be used interchangeably in API paths and CLI commands. Slugs are unique within their parent (org → workspace, workspace → project, project → environment).


Related