docs(secrets): make the credential-request tool discoverable and warn about empty hosts (#130299)

The tool page shipped with the feature but nothing pointed at it: the
tools index still listed only ask_user under human input, and neither the
secrets CLI page nor ask-user mentioned it. Add those three references.

The page also missed the trap the card invites: the allowed-hosts field
is editable, and clearing it stores a secret that can never be
substituted at egress, so the request looks successful and the credential
is unusable. Warn where the operator edits it, say what a skipped or
expired prompt means for the agent, and drop wording left over from when
requests could ask for an env value.
This commit is contained in:
Peter Steinberger
2026-08-26 11:56:12 -07:00
committed by GitHub
parent 061ac829b8
commit 6287056d26
4 changed files with 26 additions and 10 deletions
+2
View File
@@ -45,6 +45,8 @@ Related: [Secrets Management](/gateway/secrets) · [1Password plugin](/plugins/o
`openclaw secrets store` writes directly to the local shared state database. The store is Gateway-wide and team-scoped; this release accepts only `--scope team`. `--scope me` is rejected because identity scope is not supported yet.
Entries also arrive from **Settings -> Secrets** in the Control UI, and from the agent's [`secrets` tool](/tools/secrets), which asks you to type a credential into a masked prompt and stores it without the value reaching the model.
```bash
openclaw secrets store list
openclaw secrets store set <NAME>
+4
View File
@@ -31,6 +31,10 @@ You can answer from any supported conversation surface:
OpenClaw always enables a free-text **Other** answer. The agent must not add an
`Other` option to the authored option list.
Never answer `ask_user` with a credential. When the agent needs an API key it
uses the [`secrets` tool](/tools/secrets), whose masked prompt stores the value
without it entering the chat, the transcript, or the model's context.
## Platform behavior
Answers work on every supported conversation surface. The web Control UI uses a
+1 -1
View File
@@ -86,7 +86,7 @@ semantics, use [Tools and custom providers](/gateway/config-tools).
| ----------------------- | -------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| Runtime | Run commands, manage processes, use shared operator terminals, or use provider-backed Python | `exec`, `process`, `terminal`, `code_execution` | [Exec](/tools/exec), [Control UI terminal](/web/control-ui#operator-terminal), [Code execution](/tools/code-execution) |
| Files | Read and change workspace files | `read`, `write`, `edit`, `apply_patch` | [Apply patch](/tools/apply-patch) |
| Human input | Pause for a structured decision owned by the user | `ask_user` | [Ask user](/tools/ask-user) |
| Human input | Pause for a structured decision owned by the user, or obtain a credential without seeing it | `ask_user`, `secrets` | [Ask user](/tools/ask-user), [Secrets](/tools/secrets) |
| Web | Search the web, search X posts, or fetch readable page content | `web_search`, `x_search`, `web_fetch` | [Web tools](/tools/web), [Web fetch](/tools/web-fetch) |
| Browser | Operate a browser session | `browser` | [Browser](/tools/browser) |
| Operator UI | Arrange connected Control UI panes, panels, and navigation | `screen` | [Screen](/tools/screen) |
+19 -9
View File
@@ -19,8 +19,7 @@ non-primary runs do not receive it.
It is enabled by default and governed by the normal tool policy — there is no
dedicated config key. To remove it, deny it like any other tool (for example
`tools.deny: ["secrets"]` in `openclaw.json`); allowlists and tool profiles
apply to it the same way. Creating a credential request also requires an
`operator.admin` Gateway client, which the agent's own client satisfies.
apply to it the same way.
## Actions
@@ -45,11 +44,21 @@ value must enter the store, it arrives through the human prompt, the
## Answering a request
The web Control UI docks the prompt above the composer with a masked input.
The prompt always shows who is asking (agent and session), the entry name and
kind, the agent's stated reason, and — for secret entries — an editable list of
allowed hosts, so you have the final say on where the credential may be used.
If the name already exists, the prompt says so and shows when and by whom the
entry was last updated; submitting replaces the stored value.
The prompt always shows who is asking (agent and session), the entry name, the
agent's stated reason, and an editable list of allowed hosts, so you have the
final say on where the credential may be used. If the name already exists, the
prompt says so and shows when and by whom the entry was last updated;
submitting replaces the stored value.
<Warning>
Leave at least one allowed host in place. A secret with no allowed hosts is
stored but can never be substituted at egress, so the request appears to
succeed and the credential is unusable. Narrow the list rather than clearing
it.
</Warning>
Skipping the prompt, or letting it expire, tells the agent that no credential
arrived; it continues with best judgment rather than failing the turn.
iOS, macOS, and Android render the same card with a masked secret field.
@@ -59,8 +68,9 @@ a credential into a chat message is exactly what this flow exists to avoid, so
a plain-text reply is not captured as an answer.
Creating a credential request requires an `operator.admin` client (the agent's
own Gateway client qualifies). Answering needs only the normal question scope,
because answering provides a value rather than reading one.
own Gateway client qualifies) and is bound to the requesting agent run.
Answering needs only the normal question scope, because answering provides a
value rather than reading one.
## Using a stored credential