REF · STACKBONE / WIKI · v0.9.4 stackbone

client.secrets

Read workspace-encrypted secrets registered in the dashboard.

client.secrets

Typed reads of workspace-encrypted secrets. Operators register API keys, tokens and credentials in the dashboard; agents read them at runtime through client.secrets without ever seeing the ciphertext-at-rest.

Mental model

client.secrets is a thin facade over GET /api/secrets and GET /api/secrets/:name. Values are decrypted server-side and returned to the agent over a TLS-only connection authenticated by STACKBONE_AGENT_JWT. The facade does not cache — every call hits the control plane — so secret rotations propagate on the next read.

Required capability: secrets.read_write. Both get and getMany await the contract handshake before dispatching.

Read a single secret

import { createClient } from '@stackbone/sdk';

const client = createClient();

const result = await client.secrets.get('STRIPE_API_KEY');
if (result.error) throw new Error(result.error.code);

const stripeKey = result.data;

get rejects empty names with secrets_invalid_request. A name that the workspace does not have registered surfaces secrets_not_found (mapped from the underlying HTTP 404).

Read many at once

const result = await client.secrets.getMany([
  'STRIPE_API_KEY',
  'STRIPE_WEBHOOK_SECRET',
  'POSTMARK_TOKEN',
]);
if (result.error) throw new Error(result.error.code);

console.log(result.data.STRIPE_API_KEY); // string | undefined

Names absent from the workspace come back as omissions in the returned map — getMany never fails just because one secret is missing. Callers that need all-or-nothing semantics should diff the keys themselves:

const requested = ['A', 'B', 'C'];
const present = Object.keys(result.data);
const missing = requested.filter((k) => !present.includes(k));
if (missing.length > 0) throw new Error(`Missing secrets: ${missing.join(', ')}`);

Errors

Code When
secrets_invalid_request Empty name, empty array, or array with empty strings.
secrets_not_found get(name) and the workspace has no secret with that name.
secrets_invalid_response Control plane returned a payload missing the expected fields.
HTTP errors (http_*) Network / 5xx / unexpected status.

The contract gate adds contract_version_unsupported, capability_unavailable, contract_unreachable and contract_malformed — see overview.

Where to go next

  • client.config — for non-secret per-agent config (feature flags, toggles, JSON snippets).
  • client.approval — pair with client.secrets to call paid APIs only after a human approves.