secret-sharing
git clone https://github.com/benderterminal/zkettle
git clone --depth=1 https://github.com/benderterminal/zkettle ~/.claude/skills/benderterminal-zkettle-secret-sharing
SKILL.mdSecret Sharing with zKettle
Share passwords, API keys, tokens, certificates, and other sensitive data via self-destructing, one-time URLs. All encryption happens client-side — the server stores only ciphertext.
Prerequisites
This skill requires a running zKettle MCP server. If zKettle is not installed or configured, see the zKettle README for installation and MCP setup instructions. zKettle also offers a CLI, HTTP API, and Web UI — refer to the README if the MCP tools are insufficient for a particular workflow.
How It Works
- Secrets are encrypted with AES-256-GCM on the client
- The decryption key lives in the URL fragment (
) — never sent to the server#key - Secrets auto-delete after a configurable view count or time limit
- The server is zero-knowledge: it stores only ciphertext and metadata
Tools
create_secret
create_secretEncrypt and store a secret, returning an expiring URL.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| string | no | — | Plaintext to encrypt (max 500KB). Visible in conversation context — use instead for maximum security. |
| string | no | — | Read secret from this file path instead of . Keeps plaintext out of conversation. |
| integer | no | | Max views before auto-delete (1–100) |
| integer | no | | Minutes until expiry (1–43200) |
Provide exactly one of
content or file. Returns url (with decryption key in fragment) and delete_token.
read_secret
read_secretDecrypt a secret from a zKettle URL. Consumes one view.
| Parameter | Type | Required | Description |
|---|---|---|---|
| string | yes | Full zKettle URL including the fragment |
| string | no | Write decrypted secret to this file path (0600 permissions) instead of returning it |
| boolean | no | Copy to system clipboard instead of returning. Mutually exclusive with . |
Returns decrypted plaintext by default, or a confirmation message when
file or clipboard is used.
revoke_secret
revoke_secretPermanently delete a secret before it expires.
| Parameter | Type | Required | Description |
|---|---|---|---|
| string | yes | Secret ID |
| string | yes | Token returned by |
list_secrets
list_secretsList all active secrets (metadata only — no content or keys). Returns IDs, creation time, expiry, and remaining views.
generate_secret
generate_secretGenerate a cryptographically random secret. Optionally encrypt and store it in one step.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| integer | no | | Length in characters (1–4096) |
| string | no | | Character set: , , , |
| boolean | no | | If true, encrypt and store the generated secret |
| integer | no | | When , max views (1–100) |
| integer | no | | When , minutes until expiry (1–43200) |
Returns raw generated text, or
url + delete_token when create=true.
Defaults
- 1 view if
is omitted (single-use)views - 1440 minutes (24 hours) if
is omittedminutes
Limits
- 500KB max plaintext per secret
- 100 views max per secret
- 43200 minutes (30 days) max TTL
Secure Patterns
Plaintext secrets can appear in conversation context (tool inputs/outputs). Use these patterns to minimize exposure.
Creating secrets — keep plaintext out of context
— reads from file, plaintext never in tool call. Ask the user before deleting the source file afterward.create_secret(file="/path/to/secret.txt")
— generates + encrypts in one step, plaintext never in responsegenerate_secret(create=true)- Prefer these over
which puts the raw value in conversation contextcreate_secret(content="...")
Reading secrets — keep plaintext out of context
— writes to file, returns confirmation onlyread_secret(url="...", file="/tmp/secret.txt")
— copies to user's clipboard, returns confirmation onlyread_secret(url="...", clipboard=true)- Subagents can read the file at the written path without the secret entering conversation context
- Default
returns plaintext directly into conversation — warn the user before using this formread_secret(url="...") - File cleanup: Files written by
do NOT self-destruct. After the secret has been used, ask the user for permission to delete the file, then remove it. Do not leave secret files on disk.file
Common Workflows
Share a credential with someone
1. create_secret(file="/path/to/credential.txt", views=1, minutes=60) — or create_secret(content="the-password", views=1, minutes=60) if plaintext exposure is acceptable 2. Share the returned URL with the recipient
The secret vanishes after one view or 60 minutes, whichever comes first.
Rotate an API key
1. generate_secret(create=true, length=48, charset="alphanumeric", views=2, minutes=240) 2. Share the URL with the team member who needs it 3. revoke_secret(id="old-secret-id", delete_token="old-token") to kill the old one
Temporary access grant
1. create_secret(content="temp-token", views=1, minutes=30) 2. Send the one-time link — expires after a single view or 30 minutes
Audit active secrets
1. list_secrets() — review what's still live 2. revoke_secret() on any that are no longer needed
Read a shared secret
1. Receive a zKettle URL from a human or another agent 2. read_secret(url="https://example.com/s/abc123#key", file="/tmp/secret.txt") — or read_secret(url="...", clipboard=true) to copy to clipboard — or read_secret(url="...") to return plaintext directly (enters conversation context) 3. Use the decrypted content
Agent-to-Agent Secret Sharing
zKettle is well-suited for secure coordination between agents — subagents, teammates, or any multi-agent workflow where credentials need to move between contexts without leaking into conversation logs.
When to use
- A subagent needs a credential to complete its task (e.g., an engineer agent needs a deploy token)
- Agents on a team need to pass secrets to each other without the lead's context window seeing the plaintext
- A workflow generates a credential in one agent and consumes it in another
Pattern: file-based handoff (recommended)
The creating agent writes the secret to zKettle, passes only the URL to the receiving agent. The receiving agent reads it to a file, uses it, then cleans up.
Agent A (creator): 1. create_secret(content="deploy-token-xyz", views=1, minutes=30) 2. Send the URL to Agent B via message Agent B (consumer): 1. read_secret(url="...", file="/tmp/deploy-token.txt") 2. Use the file contents for the task 3. Delete /tmp/deploy-token.txt when done
The plaintext never enters either agent's conversation context — Agent A sees only the URL and delete token, Agent B sees only a confirmation message.
Pattern: generated credential handoff
When the secret doesn't need to be a specific value (e.g., a new API key, a temporary password):
Agent A: 1. generate_secret(create=true, length=48, views=2, minutes=60) 2. Send the URL to Agent B and keep the delete_token 3. After Agent B confirms usage, revoke_secret() to clean up
Guidelines
- Set
to the exact number of agents that need to read the secret — no moreviews - Use short TTLs (
) appropriate to the workflow durationminutes - The creating agent should retain the
and revoke after the workflow completesdelete_token - Prefer
on the read side so plaintext stays out of all conversation contextsfile - The receiving agent is responsible for deleting the local file after use
Gotchas
- URL fragments matter: The
portion contains the decryption key. Some tools strip URL fragments — always ensure the full URL (including#key
) is passed to#key
.read_secret - Reading consumes a view: If the secret has only 1 view remaining,
permanently destroys it. Warn the user before reading single-view secrets.read_secret
is metadata only: It returns IDs, creation time, expiry, and remaining views — never content or decryption keys.list_secrets- Conversation exposure: Using
puts the plaintext in the conversation context. Usecreate_secret(content="...")
when the user doesn't need a specific value.generate_secret(create=true)