The config store¶
The config store is what turns Hivemind from a single-operator tool into a product: per-user configuration, stored in the Hub, isolated per tenant, consumed per need. It holds the saved records that the runtimes read — how to deploy a Commander, how to run a workflow, and how each target should be gated — each owner-scoped and validated against its schema.
The store invents no new runtime. It is CRUD plus schema validation plus provenance over a small set of record types; each record is consumed by the runtime that already knows how to act on it.
The record types¶
| Record | What it configures | Consumed by |
|---|---|---|
| commander_deployments | a saved "deploy a Commander like this" — box + project + model + budget + cred refs | the remote-Commander control surface |
| workflows | a saved LLM-workflow — model, prompt, allowed actions, trigger, output, gates, budget, cred refs | the workflow runtime |
| gate_rules | per-(target, action) operator rules — auto / ask-me / never | the unified gate evaluator |
A Commander-deployment record references, rather than copies, the composed
pieces: the target box, the project the Commander coordinates, the model, and a budget
ceiling. Its per-target gate rules are not embedded — they live in gate_rules
keyed by that box. The deployment points at the box; the gate model composes the rules
for it. This compose-not-duplicate discipline runs through the whole design: one fact
lives in one place and is referenced, never mirrored.
With a saved deployment, the control surface's deploy path can consume a stored record by id — "config stored in the Hub, used per need" — instead of a raw request body.
Isolation is the point¶
Every record carries two keys:
owner_id— the per-user key within a tenant.tenant— the outer boundary.
Every read and every write filters by both, resolved from the request's verified
principal. A second user cannot read, list, or consume another user's saved
deployment — the (tenant, owner_id) filter denies. A tenant mismatch denies exactly
as a capability check denies. That cross-user isolation is the thesis proof of the
config store: the smallest meaningful test is "user B cannot see user A's config."
The schema is designed to be defense-in-depth ready. In the shared-instance model, a
per-connection tenant setting plus row-level security in the database is the backstop
so a missing WHERE clause cannot leak across tenants; in the container-per-tenant
model the container itself is the boundary and row-level security is optional. Building
the schema isolation-ready from the start costs little and keeps the shared-SaaS move a
later flip rather than a rewrite.
Tenancy models¶
Two deployment shapes reach the same product surface:
- Container-per-tenant — each customer gets their own Hub container, database, and encryption key. Isolation is the container/DB boundary: the strongest isolation, and the shape the platform runs today. Productization here is per-user config and isolation within a tenant's instance.
- Shared multi-tenant — one Hub serves many tenants; the tenant is resolved per-request from auth, with row-level isolation and per-tenant credential-key derivation. Maximum density, at the cost of moving the isolation boundary from the container to every query — the classic multi-tenant-SaaS hard problem.
The config store and credential scoping work identically in both models, so they are built first and the model choice is deferred. The near-term default is container-per-tenant with the shared-tenant seam kept live, so the shared move is a configuration flip, not a re-architecture.
Dark by default¶
The productization records land behind a flag that defaults OFF, following the same dark-launch pattern as the rest of the Hub. The record and its isolation are proven before any live deployment consumes them.