Secrets
Stored values the agent can use without ever reading them
On this page(12 sections)
- Store a secret
- Names of the stored secrets
- Make and store a random secret
- Delete a secret
- Every secret this sandbox holds, from everywhere
- Show one secret's value
- Which credentials need somebody's approval
- Put a credential behind named approvers
- Stop requiring approval for a credential
- Which secrets are host-guarded, and where they may go
- Turn a secret's host guard on or off, and set its hosts
- Ask a named person to release a credential
Write a secret, list which names exist, delete one. Revealing a value is the deliberate exception and the only route that hands one back; everywhere else the daemon substitutes a secret by reference at the moment a command runs.
12 calls. Pick one to open it, or use the list on the right.
POST/secretsStore a secret
Writes one name and value where the agent's references resolve it, without a restart: desired-state/.env once DevOps is active, the sandbox's own secret store before that.
What you send
| Field | Type | Where |
|---|---|---|
keyrequiredThe name to store it under,… | string | body |
valuerequiredThe value | string | body |
What comes back
| Field | Type |
|---|---|
okAlways true | true |
curl -X POST "$SANDBOX/secrets" \
-H "x-intentic-control: $INTENTIC_TOKEN" \
-H "content-type: application/json" \
-d '{"key":"OPENAI_API_KEY","value":"…"}'import { sandbox } from "@intentic/sandbox-client";
const result = await sandbox.secrets.set({
"key": "OPENAI_API_KEY",
"value": "…"
});GET/secretsNames of the stored secrets
Which secrets exist here. Names only, never values.
What you send
Nothing. Call it as it is.
What comes back
| Field | Type |
|---|---|
keysThe names that exist here | string[] |
curl "$SANDBOX/secrets" \
-H "x-intentic-control: $INTENTIC_TOKEN"import { sandbox } from "@intentic/sandbox-client";
const result = await sandbox.secrets.list();POST/secrets/generateMake and store a random secret
Makes a random value and stores it under a new name, where `set` would have put it, for a secret nobody has to find or paste (a session key, a signing secret, a password the task sets up itself). Answers the name and its length, never the value. Refused for a name something here already holds.
What you send
| Field | Type | Where |
|---|---|---|
keyrequiredThe name to store it under:… | string | body |
bytesHow much randomness, in bytes | integer | body |
formatHow it is spelled: `hex` (0-9,… | "hex" | "base64url" | "alnum" | body |
What comes back
| Field | Type |
|---|---|
keyThe name it is stored under | string |
lengthHow many characters it is, which… | integer |
storedWhere it was kept: desired-state/.env once… | "env" | "sandbox" |
curl -X POST "$SANDBOX/secrets/generate" \
-H "x-intentic-control: $INTENTIC_TOKEN" \
-H "content-type: application/json" \
-d '{"key":"OPENAI_API_KEY","bytes":32,"format":"hex"}'import { sandbox } from "@intentic/sandbox-client";
const result = await sandbox.secrets.generate({
"key": "OPENAI_API_KEY",
"bytes": 32,
"format": "hex"
});DELETE/secrets/{key}Delete a secret
Removes one by name.
What you send
| Field | Type | Where |
|---|---|---|
keyrequiredWhich secret, by name | string | address |
What comes back
| Field | Type |
|---|---|
okAlways true | true |
curl -X DELETE "$SANDBOX/secrets/OPENAI_API_KEY" \
-H "x-intentic-control: $INTENTIC_TOKEN"import { sandbox } from "@intentic/sandbox-client";
const result = await sandbox.secrets.remove({
"key": "OPENAI_API_KEY"
});GET/secrets/inventoryEvery secret this sandbox holds, from everywhere
One view across all the places secrets live here: what exists, where it came from and whether it is working. Never any values. This one always answers, even before there is a store to write to.
What you send
Nothing. Call it as it is.
What comes back
| Field | Type |
|---|---|
entriesOne entry per secret this sandbox… | object[] |
keyWhat identifies it | string |
kindWhere it came from: you set… | "env" | "generated" | "capability" | "provider" |
labelA friendlier name, for entries that… | string |
statusWhether it exists and, for a… | "missing" | "set" | "connected" |
requiredByWhat is waiting on it | object[] |
resourceIdWhich resource | string |
typeWhat kind of resource it is | string |
storedAtWhere it actually lives, in words | string |
revealableWhether its value can be shown… | boolean |
ciWhether a copy has been given… | object |
syncedWhether the pipeline has it | boolean |
pushedAtWhen it was last sent there | string |
lastUseThe last time an agent actually… | object |
atWhen, in milliseconds | number |
laneHow it was used: a command,… | "shell" | "code" | "browser" |
detailWhere it went: the start of… | string |
approvedByWho released it for that use,… | string |
gateWho has to release this before… | object |
approversWho may release it, by email | string[] |
scopeHow far one release goes: `use`… | "use" | "conversation" |
hostsIts host guard | object |
guardWhether a use off the list,… | boolean |
listThe hosts it goes to unasked… | string[] |
sourceWho set it: the owner, or… | "owner" | "connector" |
curl "$SANDBOX/secrets/inventory" \
-H "x-intentic-control: $INTENTIC_TOKEN"import { sandbox } from "@intentic/sandbox-client";
const result = await sandbox.secrets.inventory();POST/secrets/revealShow one secret's value
The only call that hands a value back, and it is for the owner alone. Sent as a body rather than in the address, so the name never ends up in a log or a browser's history.
What you send
| Field | Type | Where |
|---|---|---|
keyrequiredWhich secret, by name | string | body |
What comes back
| Field | Type |
|---|---|
valueThe value itself | string |
curl -X POST "$SANDBOX/secrets/reveal" \
-H "x-intentic-control: $INTENTIC_TOKEN" \
-H "content-type: application/json" \
-d '{"key":"OPENAI_API_KEY"}'import { sandbox } from "@intentic/sandbox-client";
const result = await sandbox.secrets.reveal({
"key": "OPENAI_API_KEY"
});GET/secrets/gatesWhich credentials need somebody's approval
What is gated and who may release it. Names and addresses only, never values, and the agent may read it too: knowing a credential needs Bob is what stops it concluding the account is simply not connected.
What you send
Nothing. Call it as it is.
What comes back
| Field | Type |
|---|---|
gatesEvery gate in force | object[] |
subjectWhat is gated: a secret's name,… | string |
kindWhether this gate covers one stored… | "secret" | "capability" |
approversExactly who may release it, by… | string[] |
scopeHow far one release goes: `use`… | "use" | "conversation" |
curl "$SANDBOX/secrets/gates" \
-H "x-intentic-control: $INTENTIC_TOKEN"import { sandbox } from "@intentic/sandbox-client";
const result = await sandbox.secrets.gates();PUT/secrets/gates/{subject}Put a credential behind named approvers
Names exactly who may release one secret or one connected account, and how far a single release goes. The owner's call alone. A signed-in browser or a mounted server cannot be released for one use, so those are always for the rest of the conversation.
What you send
| Field | Type | Where |
|---|---|---|
subjectrequiredWhat is gated: a secret's name,… | string | address |
kindrequiredWhether this gate covers one stored… | "secret" | "capability" | body |
approversrequiredExactly who may release it, by… | string[] | body |
scoperequiredHow far one release goes: `use`… | "use" | "conversation" | body |
What comes back
| Field | Type |
|---|---|
okAlways true | true |
curl -X PUT "$SANDBOX/secrets/gates/Fix%20the%20flaky%20parser%20test" \
-H "x-intentic-control: $INTENTIC_TOKEN" \
-H "content-type: application/json" \
-d '{"kind":"secret","approvers":["…","…"],"scope":"use"}'import { sandbox } from "@intentic/sandbox-client";
const result = await sandbox.secrets.setGate({
"subject": "Fix the flaky parser test",
"kind": "secret",
"approvers": [
"…",
"…"
],
"scope": "use"
});DELETE/secrets/gates/{subject}Stop requiring approval for a credential
Removes one gate, so the agent can use that credential the way it uses any other. The owner's call alone.
What you send
| Field | Type | Where |
|---|---|---|
subjectrequiredWhich gate, by the secret name… | string | address |
What comes back
| Field | Type |
|---|---|
okAlways true | true |
curl -X DELETE "$SANDBOX/secrets/gates/Fix%20the%20flaky%20parser%20test" \
-H "x-intentic-control: $INTENTIC_TOKEN"import { sandbox } from "@intentic/sandbox-client";
const result = await sandbox.secrets.removeGate({
"subject": "Fix the flaky parser test"
});GET/secrets/hostsWhich secrets are host-guarded, and where they may go
Every secret and connected account whose host guard is set, on or off, and its hosts. With the guard on, a use aimed off the list, or anywhere a command's text does not show, asks a person first, whatever the safety judge says. Names and hosts only, never values.
What you send
Nothing. Call it as it is.
What comes back
| Field | Type |
|---|---|
guardsEvery secret whose host guard has… | object[] |
subjectWhich secret, by the name its… | string |
kindWhether this gate covers one stored… | "secret" | "capability" |
guardOn: a use off the list,… | boolean |
hostsWhere it goes without asking while… | string[] |
sourceWho set it: the owner, or… | "owner" | "connector" |
curl "$SANDBOX/secrets/hosts" \
-H "x-intentic-control: $INTENTIC_TOKEN"import { sandbox } from "@intentic/sandbox-client";
const result = await sandbox.secrets.hosts();PUT/secrets/hosts/{subject}Turn a secret's host guard on or off, and set its hosts
Replaces one secret's host guard. Anybody who may use secrets can turn it on or take hosts away; turning it off or adding a host is the owner's: from the agent it raises a card for the owner in the live conversation and waits for their answer.
What you send
| Field | Type | Where |
|---|---|---|
subjectrequiredWhich secret, by name, or which… | string | address |
kindWhether the subject is a secret… | "secret" | "capability" | body |
guardrequiredWhether a use off the list,… | boolean | body |
hostsrequiredThe whole new list | string[] | body |
conversationIdWhich conversation to ask the owner… | string | body |
What comes back
| Field | Type |
|---|---|
guardWhether the guard is on now | boolean |
hostsWhere it goes without asking while… | string[] |
approvedByWho approved the change, when it… | string |
curl -X PUT "$SANDBOX/secrets/hosts/Fix%20the%20flaky%20parser%20test" \
-H "x-intentic-control: $INTENTIC_TOKEN" \
-H "content-type: application/json" \
-d '{"kind":"secret","guard":true,"hosts":["sandbox-a1b2c3d4e5f6.intentic.dev","sandbox-a1b2c3d4e5f6.intentic.dev"],"conversationId":"nightly-changelog"}'import { sandbox } from "@intentic/sandbox-client";
const result = await sandbox.secrets.setHosts({
"subject": "Fix the flaky parser test",
"kind": "secret",
"guard": true,
"hosts": [
"sandbox-a1b2c3d4e5f6.intentic.dev",
"sandbox-a1b2c3d4e5f6.intentic.dev"
],
"conversationId": "nightly-changelog"
});POST/secrets/requestAsk a named person to release a credential
Raises the release card in the live conversation and waits for one of the people named on it. Refused, rather than held, when there is nobody to ask: an unattended turn, no live conversation, or a click with no verified identity behind it.
What you send
| Field | Type | Where |
|---|---|---|
subjectrequiredWhat to ask for: the secret's… | string | body |
whyOne line on what it is… | string | body |
conversationIdWhich conversation to raise the card… | string | body |
What comes back
| Field | Type |
|---|---|
grantedAlways true: a refusal is an… | true |
approvedByWho released it | string |
messageWhat the grant means in practice,… | string |
curl -X POST "$SANDBOX/secrets/request" \
-H "x-intentic-control: $INTENTIC_TOKEN" \
-H "content-type: application/json" \
-d '{"subject":"Fix the flaky parser test","why":"…","conversationId":"nightly-changelog"}'import { sandbox } from "@intentic/sandbox-client";
const result = await sandbox.secrets.request({
"subject": "Fix the flaky parser test",
"why": "…",
"conversationId": "nightly-changelog"
});