OneOS Docs
Genesis 0.1.13 Console

Guides

Rotate secrets in Hives

Hives keeps a project's secrets encrypted and versioned. In this guide you load a set of secrets in one call, rotate one, confirm its version moved, read the new value back once and retire it.

You need an API key with hives:read and hives:write.

export GENESIS_API_KEY="sk_..."
export GENESIS_BASE_URL="https://os.one.ml/api"

1. Create a project

Secrets belong to a Hives project. The name carries a timestamp, because a deleted project keeps its name while it finishes deleting.

PROJECT_ID=$(curl -sf -X POST "$GENESIS_BASE_URL/v1/hives/projects" \
  -H "Authorization: Bearer $GENESIS_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"name\": \"secrets-$(date +%s)\", \"kind\": \"function\"}" | jq -er .id)
echo "$PROJECT_ID"

2. Load secrets in one call

The bulk call takes an array and creates or updates each secret by name: a new name starts at version 1, an existing one moves to its next version. Names start with a letter and use letters, digits and _; values are up to 65,536 bytes.

curl -sf -X PUT "$GENESIS_BASE_URL/v1/hives/projects/$PROJECT_ID/secrets/bulk" \
  -H "Authorization: Bearer $GENESIS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '[
    {"name": "DATABASE_URL", "value": "postgres://db1.internal/app"},
    {"name": "WEBHOOK_SIGNING_SECRET", "value": "whsec_example", "description": "Signs outgoing webhooks"}
  ]'
Response
{
  "secrets": [
    { "id": "sec_395aeb935d2642cf92d64e82933bec9a", "name": "DATABASE_URL", "description": null, "version": 1,
      "created_at": "2026-10-20T07:52:51.765251Z", "updated_at": "2026-10-20T07:52:51.765251Z" },
    { "id": "sec_d591e78ac5714ee9a9b30e05796c4ca9", "name": "WEBHOOK_SIGNING_SECRET", "description": "Signs outgoing webhooks", "version": 1,
      "created_at": "2026-10-20T07:52:51.844258Z", "updated_at": "2026-10-20T07:52:51.844258Z" }
  ],
  "success": true
}

Responses carry names and versions, never values. Operation: hives_bulk_upsert_secrets.

3. Rotate one secret

Find the secret's ID by name, then replace its value. The answer shows the new version.

SECRET_ID=$(curl -sf "$GENESIS_BASE_URL/v1/hives/projects/$PROJECT_ID/secrets" \
  -H "Authorization: Bearer $GENESIS_API_KEY" | jq -r '.data[] | select(.name == "DATABASE_URL") | .id')

curl -sf -X PUT "$GENESIS_BASE_URL/v1/hives/projects/$PROJECT_ID/secrets/$SECRET_ID" \
  -H "Authorization: Bearer $GENESIS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"value": "postgres://db2.internal/app"}'
Response
{ "id": "sec_395aeb935d2642cf92d64e82933bec9a", "name": "DATABASE_URL", "description": null, "version": 2,
  "created_at": "2026-10-20T07:52:51.765251Z", "updated_at": "2026-10-20T07:52:53.014391Z" }

Operations: hives_list_secrets, hives_update_secret.

4. Confirm the version and read the value

Reading the secret returns its metadata. Revealing returns the current value; use it only where the value is needed.

curl -sf "$GENESIS_BASE_URL/v1/hives/projects/$PROJECT_ID/secrets/$SECRET_ID" \
  -H "Authorization: Bearer $GENESIS_API_KEY" | jq '{name, version}'

curl -sf "$GENESIS_BASE_URL/v1/hives/projects/$PROJECT_ID/secrets/$SECRET_ID/reveal" \
  -H "Authorization: Bearer $GENESIS_API_KEY"
Response
{ "name": "DATABASE_URL", "version": 2 }
{ "value": "postgres://db2.internal/app" }

Operations: hives_get_secret, hives_reveal_secret.

5. Retire a secret and clean up

curl -sf -X DELETE "$GENESIS_BASE_URL/v1/hives/projects/$PROJECT_ID/secrets/$SECRET_ID" \
  -H "Authorization: Bearer $GENESIS_API_KEY"

curl -sf -X DELETE "$GENESIS_BASE_URL/v1/hives/projects/$PROJECT_ID" \
  -H "Authorization: Bearer $GENESIS_API_KEY"

Operations: hives_delete_secret, hives_delete_project.

Next

  • Rotate on a schedule from CI: give the job its own key with only hives:write and the bulk call from step 2.
  • Every secret operation: Hives API.
  • Scopes and least privilege: Scopes.

One Superintelligence, Inc. · Built from Genesis 0.1.13 and the live gateway on 2026-10-20. Support