Provision a new client
The standardized process for bringing a new client onto AcasoOS. The first decision is the deployment model; everything after follows from it. The in-repo ops counterpart is docs/runbooks/tenant-onboarding.md.
Choose the deployment model
| Question | Shared tenant | Standalone deployment |
|---|---|---|
| Where does it run? | acaso-hosted infrastructure | The client's own cloud (AWS / GCP / Azure / on-prem) |
| Isolation | Per-row, Postgres RLS on every tenant table | Whole stack, one tenant per instance (RLS still forced) |
| Bespoke agents with confidential prompts | Not recommended — loaded agents are scope-gated, not namespace-isolated | Yes — the natural home |
| Bespoke Cultivator Kinds | Yes — hard-isolated by tenant_namespace | Yes |
| Data residency / compliance demands | Limited to acaso's regions | Wherever the client runs |
| Who operates and upgrades | acaso, continuously | The client's SRE, on their own cadence |
| Time to live | Minutes | Under 4 hours with the IaC modules |
Default to a shared tenant unless the client requires their own infrastructure, strict data residency, or confidential bespoke agents. For the standalone path, follow Standalone deployment first, then return here — steps 2 onward apply identically (a standalone instance is just a deployment whose only tenant is the client; the bootstrap CLI performs step 1 for you).
Step 1 — Create the tenant
Console: Tenants → New tenant (requires acaso_os:admin). API equivalent on the admin surface (served by AgentHub, the unified gateway in dev):
curl -sS -X POST https://<host>/v1/admin/tenants \
-H "Authorization: Bearer $ADMIN_KEY" -H "Content-Type: application/json" \
-d '{
"slug": "acme-corp",
"name": "Acme Corp",
"data_residency": "us-east-1",
"active_templates": [],
"langgraph_checkpoint_retention_days": 90
}'The slug is immutable — choose it with the client. Default roles (admin, member, viewer) are installed server-side.
Step 2 — Activate templates
Pick the DataHub templates the tenant starts with and activate each. The only in-tree templates today are the examples/* ones (examples/hr_skills, examples/perf_evidence) — activate those for a demo/POC tenant only; a real client activates its own catalog (<family>/<name>) or bespoke (custom/<slug>) templates:
curl -sS -X POST https://<host>/v1/admin/tenants/acme-corp/templates \
-H "Authorization: Bearer $ADMIN_KEY" -H "Content-Type: application/json" \
-d '{"template_key": "examples/hr_skills", "version": "1.0", "config": {}}'Step 3 — Users and roles
Create the client's first users (POST /v1/users or console → Users) and bind roles. Adjust role scope bundles if the defaults don't fit — e.g. grant agents:<name>:run for each agent this client should reach. See Workflows: Manage users and Workflows: Manage roles.
Step 4 — Issue API keys
One service key per integrator system, scoped to what that system does — plus human keys for console users:
curl -sS -X POST https://<host>/v1/admin/tenants/acme-corp/api-keys \
-H "Authorization: Bearer $ADMIN_KEY" -H "Content-Type: application/json" \
-d '{
"name": "acme-jira-etl",
"kind": "service",
"role": "readwrite",
"scopes": ["primitives:write", "examples/hr_skills:write"]
}'The full key prints once in the response. Put it in the secrets manager immediately and hand it over through the normal credential-sharing process. See Workflows: Mint and revoke API keys.
Step 5 — Cultivators and connections
Bind the Cultivator Kinds the client wants (new bindings start disabled; enable deliberately), and register tenant Connections once if any bound Kind is an investigator:
curl -sS -X POST https://<host>/v1/cultivators \
-H "Authorization: Bearer $TENANT_ADMIN_KEY" -H "Content-Type: application/json" \
-d '{"kind": "skill_extractor", "enabled": true}'See Workflows: Manage cultivators.
Step 6 — Bespoke code, if any
Client-specific agents, Kinds, or templates are normal development work in the monorepo — they must already be merged and deployed before they can be activated here. Locations and rules: Develop: Overview. For bespoke agents, remember to extend ACASO_AGENT_MODULES on the deployment and grant the agent's scope to the client's roles. If the client also exposes internal (non-agent) tools over MCP, extend ACASO_MCP_TOOL_MODULES as well (agents that opt into MCP via their protocols need no extra wiring).
Step 7 — Smoke test as the tenant
curl -sS -X POST https://<host>/v1/ingest \
-H "Authorization: Bearer $NEW_TENANT_KEY" -H "Content-Type: application/json" \
-d '{"source_type": "test", "data_type": "ping", "payload": {"hello": "world"}, "idempotency_key": "onboard-smoke-1"}'Expect a 202, the worker to drain it, and one agent run end-to-end (console chat or POST /v1/agents/<name>/run).
Step 8 — Record the handoff
In the client's account file: tenant slug + UUID, every issued key and where it lives in the secrets manager, active templates and versions, cultivator bindings, data residency, and the integration plan.
De-provisioning
- Run right-to-erasure for each Person the client requests deleted.
- Revoke all of the tenant's API keys — deactivation alone does not revoke them.
- Deactivate the tenant (
DELETE /v1/admin/tenants/<slug>), then hard-delete after the contracted retention period.