opbox

Opbox is deployed one box per client. A tenant is not a row in a shared database that everyone’s data lives in together; it is its own self-contained stack, with its own Postgres, its own kernel, its own secrets, and its own front door. Inside that box sits a workspace - the wall around one client’s matters, documents, files, bills, and parties - and above it an organisation that can hold more than one workspace when a firm runs several walled-off practice areas. This page is about that model and the operator controls that run a tenant: isolation, oversight, branding, the AI cost guard-rails, and the backup, recovery, and migration seams that keep a box durable.

What it does

Two independent fences, not one. Isolation comes from a box and a database wall, and they back each other up. Each tenant’s data plane lives on an internal Docker network with no host port and no egress, so a different client is a different box entirely and there is no shared database to leak across in the first place. Even on a single box, every row is scoped to a workspace and guarded by Postgres row-level security: each kernel transaction stamps the workspace and switches to an unprivileged role, and the policies then physically refuse any row outside that workspace. It fails closed - a transaction with no workspace stamped matches no rows, never all of them. You get defence in depth without ever relying on a shared-tenant query filter being correct in every code path.

Organisation and workspace are two different grants. A workspace is one client’s wall; an organisation is the layer above it, holding several workspaces for a firm with more than one practice area. Membership in the organisation and the ability to work inside a particular client’s workspace are separate grants, never one. An organisation OVERSEER can review and read the audit trail across the organisation’s workspaces, but that is a deliberate, recorded oversight power, not a dissolving of the walls: the cross-workspace read is armed only by a checked org-membership and is inert on an ordinary workspace-scoped read, so even an overseer running a plain list sees only their home workspace. Switching the session’s active workspace re-checks access at every call against the union of home, explicit grants, and overseer membership, and never inherits the home owner bypass.

Workspace access is granted thing by thing. Reach into specific objects is handed out with an explicit, recorded grant rather than by widening someone’s standing. A grant names the actor, the thing, and the access, and can be listed and revoked, so who can touch what is always answerable and always reversible.

It carries your brand. A tenant is not a generic tool to the people who use it. Invoice branding is a first-class config row - a named theme with a logo, primary and accent colours, footer and terms text, and a header layout - and you set one of them as the firm default. The client portal carries the same idea outward: a logo, colours, a public name, and a contact route, so to a client the portal looks like your firm’s own front door.

AI spend is governed against a budget. The workspace carries a monthly AI budget held as ordinary configuration, and every governed call the agent loop makes records its own cost to an append-only ledger. An operator can read budget against spend at any time and see whether the workspace is over, and the agent loop checks the same figure before an LLM call. The cost record is written through the one front door like any other write, not a privileged shadow insert, so the spend lens reconciles by construction.

The tenant lifecycle is a governed, audited record. Standing a box up, suspending and resuming it, upgrading it, and tearing it down are owner-tier, audited transitions. The lifecycle verbs are governed record-keeping seams: they write the audited ops-event for the transition before anything changes, with the real image build, roll, and teardown handled at the operator-script edge. Deprovisioning is the only state-destroying transition and follows a load-bearing teardown order, with the final off-box archive taken before any data is destroyed.

Backup, disaster recovery, and restore. A tenant takes a scheduled, encrypted, off-box capture - the Postgres base and write-ahead log, the stored blobs, the roster, and the audit chain - encrypted before it ever leaves the box. You set the cadence, retention, destination, and data residency, and you set the recovery policy: the recovery-point and recovery-time objectives and how often a restore drill must run. A restore brings the data back first, reconciles the rest of the state from Postgres, and verifies the audit chain; if the chain is broken, the restore fails rather than bringing back a record that cannot be trusted.

Migration and cutover, one matter-type at a time. When work is being moved onto Opbox, the move is tracked per matter-type rather than as one big switch. You can read a single matter-type’s migration state, its soak-window end, whether rollback is still armed, and its residency and box placement, and list every matter-type on the box at once with its migration state and gate-readiness - the roster an operator drives a gradual cutover from. Both are projections over the audit record, not a separate store.

Host health on demand. A machine-readable host snapshot reports services, tenants, storage, and a preflight check across the whole box, and a system health read gives the live liveness signal. This is the unprivileged discovery an operator uses to see, at a glance, that the box and everything on it are well.

How you use it

Stand up a tenant. Fill every required secret, bring the stack up (migrations run themselves on boot), then run the founding genesis ceremony, which creates the workspace and the first owner, mints the standing admin bearer once, and seats the bounded chat-agent. From there every other person is seated in-app within the granted authority, never by re-running the ceremony. See Tenancy and provisioning for the full sequence.

Run several workspaces on one box, or keep them apart. A firm with internal practice areas can found more than one workspace on a single box - the RLS wall keeps each one’s data separate - and an overseer can read across them for oversight. Genuinely separate clients with distinct regulatory or confidentiality boundaries are better off on their own box, where the physical fence backs the database fence.

Watch the AI spend. Set the workspace’s monthly budget through configuration, then read budget against spend whenever you want the operator’s lens on it. The figure is computed from the cost ledger, so it is always the live number.

Set and apply the configuration. Author a tenant’s setup - templates, knowledge, policies, verb-packs - as a blueprint and apply it to the workspace; export, import, diff, and roll it back as the configuration evolves. A vertical is configuration on this box, not a gated tier.

Configure backup and recovery, and prove they work. Set the backup cadence, retention, destination, and residency, and set the recovery-point, recovery-time, and drill-cadence policy. Read the backup status and the disaster-recovery status to confirm where the box stands, and rehearse a restore on the cadence you set.

Drive a cutover. List every matter-type and its migration state across the box, read a single type’s state, soak window, and rollback-armed flag, and move work onto Opbox one type at a time rather than in a single leap.

Check the box. Run the host snapshot for a machine-readable view of services, tenants, storage, and preflight, and read the system health signal, to see the whole box at once.

The kernel verbs behind it

Every action here runs through the kernel’s one front door: each call is permission-checked, scope-checked, and audited before it executes. Most of these are owner or admin tier and are never offered to the AI - an operator runs them, and even then the permission check still applies.

Isolation and oversight:

  • acl.grant - grant access to a specific object, named and recorded.
  • acl.list - list who has been granted reach into what.
  • acl.revoke - withdraw a previously granted access.
  • config.set - set a workspace configuration value, including the AI budget and branding settings.
  • config.get - read a workspace configuration value.

AI cost control:

  • cost.budget.check - the budget-versus-spend status read: workspace budget against ledger spend, with an over-budget flag.
  • cost.query - the operator’s spend lens, aggregated from the cost ledger.
  • cost.record - append an AI-cost event to the append-only ledger, the agent loop’s governed per-call write.

Tenant lifecycle:

Backup and disaster recovery:

  • tenant.backup - a scheduled, encrypted, off-box capture (Postgres base and WAL, blobs, roster, audit chain).
  • tenant.backup.configure - set the backup cadence, retention, destination, and residency.
  • tenant.backup.status - read the current backup state.
  • tenant.restore - restore the data, reconcile from Postgres, and verify the audit chain (it fails if the chain is broken).
  • dr.policy.set - set the recovery-point and recovery-time objectives and the restore-drill cadence.
  • dr.status - read where the box stands against its recovery policy.

Configuration and migration:

  • setup.apply - apply a tenant’s setup blueprint to the workspace (with setup.define, setup.diff, and setup.rollback alongside it).
  • migration.status - one matter-type’s migration state, soak window, rollback-armed flag, and residency or box placement.
  • cutover.list - every matter-type on the box with its migration state and gate-readiness, the roster a cutover is driven from.

Host health:

  • host.doctor - a machine-readable host snapshot: services, tenants, storage, and a preflight check.
  • system.health - the live liveness signal for the box.

For how the box, the workspace RLS fence, and the organisation oversight grant fit together, see Security and permissions and Tenancy and provisioning. The full set of operator verbs lives across the tenant, dr, setup, and cost verb references.