Buckets
What buckets are
A bucket is a named, durable collection of knowledge. Agents search buckets, ingestion writes into buckets, and the bucket slug is the human-readable handle (support-handbook, pricing, legal). Bucket ids are stable machine handles; slugs are unique per team.
List buckets
GET /v1/buckets
Authorization: Bearer sk-...
Optional: ?include_archived=true. The response is scoped to your key's team and returns, per bucket: id, slug, name, status, member counts, and store readiness. Use returned ids or slugs anywhere a {bucket} path segment is accepted.
Create a bucket
POST /v1/buckets
Authorization: Bearer sk-...
Content-Type: application/json
{
"name": "Support Handbook",
"slug": "support-handbook",
"description": "Canonical support articles"
}
Requires the knowledge:bucket:create capability. The slug is the idempotency identity: a collision with an Idempotency-Key replays the existing bucket (200 + Idempotent-Replayed: true); without one it is 409 bucket_slug_exists.
Create-on-first-use
PUT /v1/buckets/{slug}
Authorization: Bearer sk-...
Idempotent ensure-by-slug: 201 when created, 200 ("created": false) when it already exists. This is the recommended way for scripts to provision destinations before uploading — explicit, idempotent, and separate from the upload call.
{ "id": "bucket_abc", "slug": "support-handbook", "status": "active", "created": true }
Concurrency is a success case, not an error: when two callers ensure the same slug at the same moment, the one that loses the race re-reads and returns the winner's bucket with "created": false. Parallel pipeline runs can safely call this on every run.
create_missing_buckets: true on upload bodies — still works on the alias routes, but provisioning inside an upload call hides an important side effect. Prefer PUT /v1/buckets/{slug}.Read one bucket
GET /v1/buckets/{bucket}
Id or slug; archived buckets are readable (a read never hides a bucket the delete surface can still address). Same payload shape as one item of the bucket list, including member counts and store readiness.
Membership
GET /v1/buckets/{bucket}/sources List members: id, type, title, status, ready
DELETE /v1/buckets/{bucket}/sources/{id} Detach a source from this bucket only
Detaching removes the membership and the bucket's search-index copy; the canonical source, its storage, and its other bucket memberships are untouched.
Canonical routes and aliases
/v1/buckets is the canonical Manage surface — list, create, ensure-by-slug, read, membership, and delete all live there. The permanent alias surface is exactly two routes: GET /v1/knowledge/buckets (list) and POST /v1/knowledge/buckets (create). Read, ensure-by-slug, membership, and delete have no alias and live only under /v1/buckets.
Alias responses advertise the successor via Deprecation: true and Link: </v1/buckets>; rel="successor-version" headers, with no sunset date — the alias is not scheduled for removal, and integrations calling it (including the MCP server and the dashboard) keep working unchanged.
Deleting sources globally
DELETE /v1/sources/{id}
POST /v1/knowledge/files:delete Bulk (up to 100 ids)
The bulk body is {"file_ids": ["...", ...], "force": true} — the field is
file_ids (max 100); force behaves per item exactly like the single
delete.
Global delete removes the source everywhere: storage, search-index copies, and every bucket membership. Without force=true it is blocked (409 delete_blocked) when dependents exist — bucket memberships count as dependents, as do agent policies, widgets, and workflows referencing the source; details.dependencies enumerates them.
Delete a bucket
Deleting a bucket cascades over its member files — storage, search-index
copies, and policy references are all removed. It requires the explicit-only
knowledge:bucket:delete capability and force=true:
DELETE /v1/buckets/{bucket}?force=true
Authorization: Bearer sk-...
{bucket} accepts an id or slug; archived buckets are deletable too. Without
force=true the call is refused with 400 force_required.
The response is a cascade manifest, not a bare boolean:
{
"object": "bucket_deleted",
"ok": true,
"bucket_id": "bucket_abc",
"deleted_bucket": true,
"requested_files": 3,
"deleted_files": 3,
"already_missing_files": 0,
"failed_files": 0,
"items": [ { "file_id": "file_1", "status": "deleted" } ],
"bucket_status": "deleted",
"request_id": "req_..."
}
bucket_status is "deleted" on success and "restored_partial_failure"
when a member failed and the bucket was restored for retry. While a cascade
is running, a second delete answers 409 delete_in_progress (retryable).
What a later retry sees depends on how the cascade ended: after a fully
successful cascade the bucket is gone and retries return 404; after a
partial failure the bucket is restored with its surviving members, and a
retry returns 200 and re-runs the cascade (see the retryable semantics
above).
Semantics to rely on:
- No soft-delete. Once the delete completes (
deleted_bucket: true), a retry returns404 bucket_not_found. - Partial failure keeps evidence — and stays retryable. If any member
fails to delete, the bucket and its store are retained with the failed
members (
ok: false,deleted_bucket: false); inspectitems[]. A retry returns200and re-runs the cascade: already-deleted members are counted asalready_missing_files, and once every member succeeds the bucket itself is removed. Only after that does the endpoint start returning404. - One capability authorizes the whole cascade.
knowledge:bucket:deletealone covers the member-file deletions —knowledge:file:deleteis not additionally required (bucket delete is the strictly stronger grant). Detaching a single file from the bucket without deleting it (DELETE /v1/buckets/{bucket}/sources/{id}) is the operation that requiresknowledge:file:delete. - Detaching a file from one bucket without deleting it stays
DELETE /v1/buckets/{bucket}/sources/{id}(see Membership above).
Connecting buckets to agents
An agent's saved policy names the buckets it searches. calypso-agent uses the workspace default policy; named agents (calypso-agent:{agent_id}) can each point at different buckets. See Agents.