sc run and phantoms: use a key without seeing it
The one habit that makes SafeClaw work: the agent handles phantoms, never
values. A phantom is a placeholder like __sc__github__. Put it exactly
where the credential would go, prefix the command with sc run --, and the
proxy substitutes the real value at egress, only toward that connection's own
hosts.
The pattern
HF_TOKEN=__sc__hf_token__ sc run -- python train.py
The env var carries the phantom, not a value. Nothing in the agent's world
ever holds the token; the swap happens inside the proxy, on the way to
huggingface.co and nowhere else. No approval ceremony per read, because
nothing is revealed.
Three steps, always the same:
- Find the phantom.
sc connection lslists every connection with its hosts and phantom (agents readGET /v/<vault>/registryinstead). Copy it verbatim; never construct one by guessing. - Place it where the credential belongs: an env var a tool reads, an
Authorizationheader, a config file, even a URL path (https://api.telegram.org/bot__sc__telegram__/sendMessage). - Route the command through
sc run --. Unrouted traffic is untouched, and an unrouted phantom reaches the upstream as a literal string: a clean 401, never a leak.
Multi-account
Accounts are distinguished by phantom value, not env-var name. Same
GITHUB_TOKEN variable, different phantom:
GITHUB_TOKEN=__sc__github__ sc run -- gh pr list # personal
GITHUB_TOKEN=__sc__github_work__ sc run -- gh pr list # work
Approvals mid-run
A policy-gated use fails the command with an approval link in its error
output. Open the link, tap your passkey, re-run the exact same command; the
approval is cached. Agents background sc op wait <op_id> and treat its exit
as the signal (0 = approved).
The anti-pattern: $(sc get)
If you learned other secret managers first, this feels natural:
HF_TOKEN=$(sc get HF_TOKEN) python train.py # don't
It runs, but it defeats the point. The plaintext now sits in the process
environment where the agent, python, and every child process can read it,
and you paid a passkey ceremony for the privilege: every sc get is
approval-gated because it reveals a value. You have reproduced "paste the key
into the env" with extra steps.
sc get exists for you at a terminal: a one-off curl you type yourself,
checking what's stored, migrating away. It is not an agent primitive.
Debugging a 401/403
On a brokered call, an auth failure is usually routing, not the credential. Check in order:
- Did the command actually run under
sc run --? - Is the phantom verbatim from
sc connection ls(or the registry)? - Is the destination one of that connection's hosts?
- Still failing:
sc doctor, and the error'sSafeClaw: <code>line maps to a fix in DIAGNOSTICS.md.