Provisioning data resources
Databases, object storage, and Redis all follow the same three-beat pattern: provision → attach → reveal. Provisioning creates the resource inside your project; attaching wires its connection details into a service as env vars; revealing hands you the raw credentials when a tool or a human needs them directly.
The env-var key names are a stable contract — a value can change if a resource is migrated to a different backend, but the key never does. Injected vars take effect on the service’s next deploy or restart.
Databases (Postgres / MySQL)
{ "name": "provision_database",
"arguments": { "projectId": "…", "kind": "postgres", "attachServiceId": "…" } }
kindselects the engine (Postgres or MySQL).provision_databasecreates the database + user on the platform’s host engine, encrypts the password, and — becauseattachServiceIdis set — auto-creates aDATABASE_URLruntime env var on that service. OmitattachServiceIdto provision unattached and wire it up later.reveal_database_credentialsreturns the full bundle (host, port, db name, user, password, connection URL) using the internal docker-bridge host that services inside the platform use. Every reveal is audit-logged.
Reaching a database from outside the platform
For local development or an external tool, use the public host and an IP allowlist:
add_database_allowlistwith acidr(typically a/32) and optionalttlHours. This adds a rate-limited firewall rule plus an engine-level grant scoped to this DB’s role from this source — cross-tenant probes are refused at the protocol level.reveal_database_public_credentialsreturns credentials with the public hostname. The URL only connects from an allowlisted IP.list_database_allowlist/remove_database_allowlistmanage the entries.
Object storage (S3-compatible buckets)
{ "name": "create_bucket",
"arguments": { "projectId": "…", "label": "uploads", "attachServiceId": "…" } }
create_bucket mints scoped credentials and, when attachServiceId is set, injects six runtime env vars: S3_ENDPOINT, S3_REGION, S3_BUCKET, S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY, S3_FORCE_PATH_STYLE.
attach_bucket_to_service/detach_bucket_from_serviceinject or remove those six vars on any service (idempotent). Detaching keeps the bucket and its objects; only the service’s access goes away.reveal_bucket_credentialsreturns the full credential bundle for an unattached service, a local dev env, or a tool that doesn’t read env vars. Audit-logged; the secret grants full read/write.list_bucketsshows buckets in a project and which services each is attached to.
Browser uploads (CORS)
If a browser app makes direct pre-signed GET/PUT requests to a bucket, set a CORS policy:
{ "name": "set_bucket_cors",
"arguments": { "bucketId": "…", "rules": [
{ "allowedOrigins": ["https://app.example.com"],
"allowedMethods": ["GET", "PUT", "HEAD"] } ] } }
set_bucket_cors replaces the whole policy (it is not a merge). get_bucket_cors reads the current rules. CORS is enforced by the browser only — it is not access control. A private bucket stays private; every request still needs a signed URL. Avoid "*" origins in production.
Redis / Valkey
Provisioning is asynchronous:
{ "name": "provision_redis",
"arguments": { "projectId": "…", "tier": "default", "attachServiceId": "…" } }
provision_redis returns immediately with status='provisioning'. tier sets memory: small = 128MB, default = 256MB, large = 1024MB. It is subject to the deploy gate and a host RAM budget (returns quota_exceeded when full).
- Poll
list_redisuntil the instance reportsstatus='ready'. reveal_redis_credentialsreturns host/port/password and the fullREDIS_URL(redis://:<password>@…:<port>/0) — only onceready.attach_redis_to_service/detach_redis_from_serviceinject or removeREDIS_URL(idempotent; instance must beready).
Instances are durable by default (AOF persistence) and reachable from the project’s services over the internal network.
Deleting
Deletes are destructive and mostly irreversible — see Deleting resources for delete_database, delete_bucket, and delete_redis and exactly what each removes vs preserves.