Skip to content

Grants

A grant gives an agent or tool read access to a fixed set of secrets, for a limited time, through a key that is deliberately not yours.

murk agent grant --name NAME --only KEY [--ttl DUR] mints a fresh, ephemeral age identity: never your MURK_KEY. The grant becomes a recipient of the encrypted meta blob, so it can verify vault integrity and read group/grant state, but it’s excluded from the everyone layer entirely. Its actual access is the set of --only keys, each re-encrypted as a private ciphertext addressed to the grant’s own pubkey; nothing else in the vault decrypts for it, shared or otherwise.

The key is written to ~/.config/murk/agent-keys/<vault-hash>-NAME (or --out PATH, or --out - to stream it instead of writing a file). It’s a bearer credential: whoever holds it has the access it grants, so treat the file like the secrets it unlocks.

Point the agent at the grant key and mark it as an agent context:

Terminal window
MURK_KEY_FILE=~/.config/murk/agent-keys/<vault-hash>-codex MURK_AGENT=1 \
murk agent exec --only STRIPE_SECRET_KEY -- python scripts/refund.py

MURK_AGENT=1 forces strict mode for that process, so it can never fall back to your stored key in ~/.config/murk/keys even if MURK_STRICT isn’t otherwise set: it must present the grant key or fail closed. murk agent init does the whole safe-path setup (optionally setting the allow-list, minting the grant, and printing the exact run command) in one step. See Environment variables for what each variable does, and AI agents & MCP for the full walkthrough, including serving a grant over MCP with murk mcp.

Scope is a hard, cryptographic boundary: a grant cannot decrypt a key it wasn’t given, because no ciphertext exists for its pubkey. On top of that, the vault’s optional agent policy (murk policy set --allow-tag TAG) is a second, binary-enforced guardrail: once set, a secret can only be granted or injected in agent mode if its schema carries an allowed tag, with no override flag. That’s a guardrail enforced by the murk binary at its agent entry points, not a sandbox or an access-control system: a compromised agent process, or a human with age and the raw key, is outside what any of this stops. See the threat model for the full boundary.

--ttl (default 2h) is recorded in the grant’s metadata alongside its scope and issuer. The TTL is advisory (age keys can’t self-destruct, and old vault versions stay decryptable from git history), so it tells you when to act, not a guarantee that access stops on its own. murk agent ls lists active grants with their scope and TTL status (time remaining, or how long expired) and works offline.

murk agent revoke NAME [--rotate] removes the grant and its ephemeral recipient, clearing its private ciphertexts so it can no longer read current values. Because the key could still decrypt old .murk versions from git history, revocation doesn’t erase git history: --rotate re-prompts for new values across the grant’s scope, which is the step that actually closes the exposure.

The grants map lives inside the encrypted meta blob, not the plaintext header, so an agent’s existence and its scope don’t leak to anyone without a key. See Vault format for the full on-disk layout, and Recipients & signatures for how that meta blob is protected against tampering.