Skip to main content
Per-agent settings that live outside the agent’s files: personality slider values, installed skills, and, for OpenClaw agents, command-execution settings and standing exec grants. Use this page when you script agent setup or audit what an OpenClaw agent may run without asking. Examples use the default port 18790 and no access token. With STUDIO_ACCESS_TOKEN set, add -b 'clawboo_access=<token>' to each curl. Every route is on the general rate limit; the revoke also counts against the stricter sensitive limit (see the REST API overview). Errors use { "error": "<message>" } unless a section shows otherwise. A Clawboo Native agent’s command access is a separate switch, /api/agents/:agentId/shell, documented in the Agents API.

Routes

Personality

The six personality sliders and an optional custom text, stored on the agent row as { values, customText }. The server does not read these values when it builds a prompt. The dashboard turns them into a personality section in the agent’s SOUL.md and saves that file separately, through PUT /api/agents/:agentId/files/SOUL.md. Calling this route alone does not change how an agent behaves. The dashboard uses values from 0 to 100. The server stores any values object without checking its keys. When the dashboard reads older values, it maps verbosity to glass, humor to bite and caution to spine, and drops formality and speed_cost.

GET /api/personality

  • Query params: agentId (required).

Responses

200 OK: the stored values, or nulls when nothing is stored or the stored value cannot be read:
400 Bad Request: { "error": "agentId required" }. 500 Internal Server Error: a database failure, { "error": "<message>" }.

Example

POST /api/personality

Saves the values. An agentId with no agent row gets a placeholder row (named after the id).
  • Request body:

Responses

200 OK: { "ok": true }. 400 Bad Request: { "error": "invalid JSON" } when the body is not a JSON object, or { "error": "agentId and values required" }. 500 Internal Server Error: a database failure, { "error": "<message>" }.

Example

Skills

A skill row records that one or more agents have a skill. The skill then shows on those agents in the Capabilities panel and on the graphs (it is a skill record in GET /api/capabilities). This route only records the skill: it downloads and runs nothing. The Marketplace installs skills through it with source: "curated". Each row lists its holders in metadata.agentIds, so one row can serve several agents:
Skill routes answer errors as { "ok": false, "error": "<message>" }.

GET /api/skills

Lists skills, newest first.
  • Query params: agentId (optional): only skills this agent holds.

Responses

200 OK: { ok: true, skills: SkillRow[] }. 500 Internal Server Error: { ok: false, error: string, skills: [] }.

Example

POST /api/skills

Installs a skill on one agent. Before anything is stored, Clawboo’s prompt-injection scan checks the name, source, category and the whole request body, at its strictest setting, where every finding blocks the install except a bidirectional-text isolate character, which is let through. A blocked install answers 422; blocked and clean installs both write an audit row. An existing skill gains the agent as a holder; otherwise a new row is created.
  • Request body:

Responses

200 OK: { ok: true, skill: SkillRow | null }. 400 Bad Request: { "ok": false, "error": "Invalid JSON body" }, or { "ok": false, "error": "id, name, source, and agentId are required" } when a required field is not a non-empty string or category is not a string. 422 Unprocessable Entity: the scan blocked the install. The audit row keeps only pattern, line and fingerprint for each finding:
500 Internal Server Error: { ok: false, error: string }.

Example

DELETE /api/skills

Removes one agent from a skill. When no holder is left, the row is deleted.
  • Query params: id (the skill id) and agentId, both required.

Responses

200 OK, one of:
removedRow: false means other agents still hold the skill. deleted: true does not confirm that this agent held it. 400 Bad Request: { "ok": false, "error": "id and agentId query params are required" }. 500 Internal Server Error: { ok: false, error: string }.

Example

Exec settings

Each agent’s command-execution choice, stored on the agent row (exec_config) as { execAsk, execSecurity? }. Only OpenClaw enforces it: for an OpenClaw agent, POST also writes the choice into the OpenClaw Gateway’s exec-approval policy, the copy OpenClaw checks before it runs a command. The dashboard shows this control, Command Execution on the agent’s Permissions tab, for OpenClaw agents only. On every other runtime the value is stored and nothing enforces it. Claude Code, Codex and Hermes run with their own approval prompts turned off; see What agents can do. execSecurity is stored but never sent to OpenClaw.
POST /api/exec-settings replaces the whole stored value. A Claude Code, Codex or Hermes agent keeps the model and provider picked for it in that same field. Posting here for one of those agents drops that choice, and the agent falls back to its default model.

GET /api/exec-settings

Reads Clawboo’s stored copy, not OpenClaw’s policy. To see what OpenClaw holds, read storedAsk from GET /api/exec-allowlist.
  • Query params: agentId (required).

Responses

200 OK: the stored value, or null when nothing is stored. Other fields stored in the same place come back too:
400 Bad Request: { "error": "agentId required" }. 500 Internal Server Error: a database failure, { "error": "<message>" }.

Example

GET /api/exec-settings/all

Every agent’s stored execAsk, keyed by agent id. Agents with nothing stored, or whose stored value has no string execAsk, are left out.

Responses

200 OK:
500 Internal Server Error: a database failure, { "error": "<message>" }.

Example

POST /api/exec-settings

Stores the value first, then, for an OpenClaw agent, writes it into OpenClaw’s policy under OpenClaw’s own id for the agent. A refusal from the Gateway never loses what you sent. An agentId with no agent row gets a placeholder row (named after the id).
  • Request body:

Responses

200 OK: stored, and OpenClaw accepted the setting:
200 OK: stored, with no OpenClaw policy to write. This is the answer for every other runtime, and for an OpenClaw agent row with no OpenClaw id:
400 Bad Request: { "error": "invalid JSON" } when the body is not a JSON object, or { "error": "agentId and values required" }. 400 Bad Request: an OpenClaw agent with an execAsk other than off, on-miss or always. The value is already stored by then; on other runtimes any string is stored and answered not-applicable:
502 Bad Gateway: stored in Clawboo, but the Gateway refused it, so what the agent is held to did not change. ok is false and savedLocally is true:
After a 502, GET /api/exec-settings returns the value you sent, not the one in force. Retry until the POST answers 200, or read storedAsk from GET /api/exec-allowlist to see what OpenClaw holds. 500 Internal Server Error: a database failure, { "error": "<message>" }.

Example

Standing exec grants

The commands an OpenClaw agent may already run without asking, and the way to take them back. Answering Always to a command prompt creates such a grant. These two routes back the Commands this Boo can run without asking card on the agent’s Permissions tab. Only OpenClaw keeps standing exec grants, so both routes are OpenClaw-only. The read never calls the Gateway, because OpenClaw’s read call (exec.approvals.get) also writes the policy back. Instead it opens OpenClaw’s state database read-only at <state dir>/state/openclaw.sqlite. The state dir is OPENCLAW_STATE_DIR (or the older MOLTBOT_STATE_DIR or CLAWDBOT_STATE_DIR) when set, otherwise ~/.openclaw, or an existing ~/.clawdbot or ~/.moltbot when ~/.openclaw does not exist. The policy’s internal socket token is never returned. Only the revoke talks to the Gateway.
An empty list is a safety claim, so these routes never produce one by accident. “No grants”, “no policy on this machine” and “a policy that could not be read” are three different answers with three different state values. Never show unreadable as an empty list: those grants are still on disk and still enforced.

GET /api/exec-allowlist

Reads one agent’s grants from OpenClaw’s stored policy, plus the fleet-wide * entry. OpenClaw applies the fleet-wide rows to this agent too, but they are not this agent’s to revoke, so the two lists are returned separately.
  • Query params: agentId (required): Clawboo’s id for the agent. The route looks up OpenClaw’s id itself.

Responses

200 OK, state: 'ok': the policy was read. entries is this agent’s own list, the only rows a revoke can remove:
200 OK, state: 'absent': there is no policy on this machine, so nothing is granted to any agent:
200 OK, state: 'not-applicable': the agent is not on OpenClaw, or its row has no OpenClaw id:
502 Bad Gateway, state: 'unreadable': the policy exists and could not be read. The counts come from the last successful save and cover every agent in the policy, not only this one (both are 0 when the database itself could not be opened). This response has no entries key, so a client cannot mistake it for an empty list:
400 Bad Request: { "error": "agentId required" }. 404 Not Found: { "error": "agent not found" }. 500 Internal Server Error: any other failure, redacted, { "error": "<message>" }.

Example

POST /api/exec-allowlist/revoke

Removes rows from one agent’s own list. The Gateway has no call that removes one row, so the route rewrites OpenClaw’s whole policy through the Gateway, with a check that nothing else changed it in between. Every other agent’s policy is carried over unchanged; this agent keeps its own security and ask; an emptied list is kept rather than removed. Success is checked against the policy the Gateway returns after the write. On the sensitive rate limit as well as the general one.
  • Request body:
Pass key values back exactly as the GET returned them: a key is a fingerprint of the row’s pattern, argPattern and source, not an id. Revoke a grant made with Always together with its node-marker row, in the same call.

Responses

200 OK, outcome revoked: the rows are gone, confirmed against the Gateway’s reply. remaining counts the rows this agent still has:
409 Conflict: nothing was written. One of:
blocked-wildcard means a key is also in the fleet-wide * entry, so removing this agent’s copy would leave the command allowed. One such key refuses the whole call; keys names them. 502 Bad Gateway, outcome not-verified: the write went through, but the Gateway’s reply still lists those rows, or came back with no policy to check:
not-verified is the one outcome that is not a no-op: the write landed and could not be confirmed. Read GET /api/exec-allowlist again before you act, and do not report the grant as gone.
502 Bad Gateway: the Gateway call failed (for example, no Gateway connection). Its message is passed through, redacted:
400 Bad Request: no agentId, or keys is missing, empty, longer than 200, or holds a non-string or empty entry:
400 Bad Request: the agent is not on OpenClaw, or its row has no OpenClaw id:
404 Not Found: { "error": "agent not found" }. 429 Too Many Requests: the sensitive limit:

Example

Source of truth: apps/web/server/api/personality.ts, skills.ts, execSettings.ts and execAllowlist.ts; the OpenClaw policy read is apps/web/server/lib/agentSource/openclawExecAllowlistRead.ts, the policy write is packages/gateway-client/src/execApprovals.ts, the revoke execRevoke.ts, and the row classes execAllowlist.ts.
Last modified on October 31, 2026