The handbook
TroubleshootingLocal developmentDeploymentProvision a new clientStandalone deploymentUpgradesArchitecture
Operate

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

QuestionShared tenantStandalone deployment
Where does it run?acaso-hosted infrastructureThe client's own cloud (AWS / GCP / Azure / on-prem)
IsolationPer-row, Postgres RLS on every tenant tableWhole stack, one tenant per instance (RLS still forced)
Bespoke agents with confidential promptsNot recommended — loaded agents are scope-gated, not namespace-isolatedYes — the natural home
Bespoke Cultivator KindsYes — hard-isolated by tenant_namespaceYes
Data residency / compliance demandsLimited to acaso's regionsWherever the client runs
Who operates and upgradesacaso, continuouslyThe client's SRE, on their own cadence
Time to liveMinutesUnder 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):

bash
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:

bash
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:

bash
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:

bash
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

bash
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

  1. Run right-to-erasure for each Person the client requests deleted.
  2. Revoke all of the tenant's API keys — deactivation alone does not revoke them.
  3. Deactivate the tenant (DELETE /v1/admin/tenants/<slug>), then hard-delete after the contracted retention period.
PreviousOperateDeploymentNext OperateStandalone deployment