pulse > context — ZSC CLI commands
The Pulse terminal in the workbench exposes the ZSC vault as a flat
set of subcommands under context. Every command hits an
admin-gated /api/zsc/* route (using the same admin cookie the
session uses for everything else), renders the result as a card, and
writes a row to the entangled state so the operation appears in the explorer.
CLI source: shared/pulse/src/cli/commands.ts.
API surface: /api/zsc/*.
Subcommand index
| Command | API route | Notes |
|---|---|---|
context list | GET /api/zsc/list | Render every secret as a card with name, owner, last-read, read-count. |
context info <name> | GET /api/zsc/info/:name | Drill into one secret. |
context set <name> <value...> | POST /api/zsc/set | Create or replace. Value captured from raw line — multi-word values supported. |
context rotate <name> | POST /api/zsc/rotate/:name | Re-encrypt with fresh IV. |
context grant <name> <zid> | POST /api/zsc/grant/:name | Add ZID to permissions. |
context revoke <name> <zid> | POST /api/zsc/revoke/:name | Remove ZID from permissions. |
context audit <name> [--limit N] [--verify] | GET /api/zsc/audit/:name | Recent chain rows; --verify re-derives every proof. |
context delete <name> (alias: context rm <name>) | DELETE /api/zsc/:name | Irreversible. Prompts for confirmation. |
Examples
Adding the Stripe live key
pulse> context set STRIPE_SECRET_KEY sk_live_51ABC...XYZ
✓ Set
name STRIPE_SECRET_KEY
encrypted_at 2026-05-17T13:42:11Z
audit_row 8a1f2c… (proof verified)
The CLI never echoes the plaintext back — only the metadata. The
plaintext is captured from ctx.raw.indexOf(name) so spaces or quotes
in the value pass through verbatim.
Listing the vault
pulse> context list
OPENAI_API_KEY owner=ZEQ-SYS reads=184 last=2289605442
STRIPE_SECRET_KEY owner=ZEQ-FOUNDATION reads=47 last=2289605501
SENDGRID_API_KEY owner=ZEQ-SYS reads=12 last=2289602100
3 secrets · all rotated within 18.6 h target
Granting a ZID
pulse> context grant STRIPE_SECRET_KEY ZEQ07111111111
✓ Granted
name STRIPE_SECRET_KEY
zid ZEQ07111111111
permissions [ZEQ07111111111]
audit_row 61b34d… (purpose=granted)
Inspecting the entangled state
pulse> context audit STRIPE_SECRET_KEY --limit 5
[2289605501] secret_rotated ZEQ-SYS cd91f4… auto_rotated
[2289605442] secret_read ZEQ-FOUNDATION f4ce81… read
[2289605300] secret_read ZEQ-FOUNDATION 9a2c11… read
[2289500001] secret_set ZEQ-FOUNDATION 8a1f2c… created
[2289499900] secret_set ZEQ-FOUNDATION c3df45… granted
5 rows · chain head = cd91f4… · prev_hash linkage OK
Add --verify to re-derive every proof_digest and confirm
linkage byte-for-byte:
pulse> context audit STRIPE_SECRET_KEY --verify
✓ 5/5 proofs match
✓ 5/5 prev_hash links chain correctly
✓ Chain head verified
Probing permissions
pulse> context probe STRIPE_SECRET_KEY ZEQ07222222222
✗ Denied
reason denied
hint ZID not in bound_zid (ZEQ-FOUNDATION) or permissions []
Grant with: context grant STRIPE_SECRET_KEY ZEQ07222222222
Rotating manually
pulse> context rotate STRIPE_SECRET_KEY
✓ Rotated
name STRIPE_SECRET_KEY
iv_before 446bc1e2... (8 bytes shown)
iv_after 93491d79... (8 bytes shown)
audit_row cd91f4… (purpose=manual_rotated)
Deleting (irreversible)
pulse> context delete LEGACY_API_KEY
! Confirm: delete LEGACY_API_KEY? This is irreversible. [y/N]
> y
✓ Deleted
name LEGACY_API_KEY
audit_chain preserved (12 rows survive)
vault_row dropped
The audit entangled state survives — every prior secret_read, secret_set,
secret_rotated, secret_denied row remains as the forensic record
that the secret existed.
How context set captures multi-word values
A vault value like sk_live_xxx is one token, but configuration
strings with spaces happen — connection URIs, JSON blobs, BASIC-auth
headers. The CLI captures from ctx.raw.indexOf(name) so:
pulse> context set DATABASE_URL postgres://user:pass with space@host/db
stores the full string verbatim. The shell never sees this — Pulse's own CLI parser handles it before the value would leak to a process arg list.
Companion surfaces
- Admin UI:
/portal/secrets/— same 8 operations as a clickable surface (4-stat dashboard, table, drawer, modal) - HTTP API:
/api/zsc/*— same operations as raw HTTP for scripted ops
Auth
Same authentication path as the rest of the workbench Pulse: the
admin cookie issued at /admin/ sign-in. There's no separate
"context" auth — if you can open the Pulse panel in the workbench,
you can run context commands.
For operators who want narrower scope, write a Pulse-side macro that
calls context probe before context set — the probe is safe to
expose to less-privileged scripts because it never returns plaintext.
Related
- ZSC Secure Context — what the vault is
- ZSC Audit Trail — what
--verifyactually checks - Operate → ZSC Bootstrap — master-key + KMS adapter setup
/api/zsc/*— the HTTP surface the CLI calls