Skip to content
Back to skills

Secrets Vault

ASecurity

Encrypted-in-repo secret vault (SOPS + age) so a lost laptop never means lost keys: every project's secrets are committed to git as age CIPHERTEXT and a fresh `git clone` + ONE master key restores everything (`sops -d`). A repo leak yields only ciphertext. Implements the R-SECRETS-VAULT doctrine. Use when the user says "vault", "encrypt my secrets", "secret backup", "recover my keys", "commit my API keys", "sops", "age", "never lose a key", or in French "coffre-fort", "chiffrer mes secrets", ...

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 2, 2026
ai-agentspythongobashnodegitapi

Works with

  • api

Security analysis

A100/100

Pro scans all 6 files and shows the line behind each finding

Scanned October 2, 2026

npx -y skills add agentik-os/claude-code-skills --skill secrets-vault --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Secrets Vault?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Secrets Vault
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/agentik-os-secrets-vault/badge)](https://www.skillsdirectory.com/skills/agentik-os-secrets-vault)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: secrets-vault
description: >
  Encrypted-in-repo secret vault (SOPS + age) so a lost laptop never means lost keys: every
  project's secrets are committed to git as age CIPHERTEXT and a fresh `git clone` + ONE master
  key restores everything (`sops -d`). A repo leak yields only ciphertext. Implements the
  R-SECRETS-VAULT doctrine. Use when the user says "vault", "encrypt my secrets", "secret backup",
  "recover my keys", "commit my API keys", "sops", "age", "never lose a key", or in French
  "coffre-fort", "chiffrer mes secrets", "sauvegarder mes cles", "recuperer mes cles". NOT for
  live secret INJECTION into a running app (that stays a plaintext .env in ~/.omega); NOT for
  public repos (they NEVER carry ciphertext).
argument-hint: "init <repo> | add <src> <vault> <restore> | verify <vault> | restore [vault]"
allowed-tools: ["Bash", "Read", "Write"]
domain: safety
read_only: false
triggers: ["vault", "encrypt my secrets", "secret backup", "recover my keys", "commit my api keys", "sops", "age", "never lose a key", "coffre-fort", "chiffrer mes secrets", "recuperer mes cles"]
---

# secrets-vault — encrypted-in-repo secret recovery (SOPS + age)

The operator's hard goal: **lose the laptop, clone the GitHub repo, recover ALL API keys.** This
skill delivers exactly that, safely, under **R-SECRETS-VAULT** — a *narrowing* of L0/R-ENV, never
an exception:

- Plaintext secret values + the master private key **never** touch a repo. `~/.omega` stays the
  plaintext source of truth; the vault is its **encrypted recovery mirror**.
- Only **age ciphertext** whose plaintext is machine-verified absent is committable, and **only to
  a PRIVATE repo**. Public repos (OmegaOS, rmux) carry ciphertext **never** (harvest-now-decrypt-
  later + readable key names are a permanent leak).
- One master age keypair at `~/.omega/secrets/age/master.txt` (chmod 600). Its **public** recipient
  is committed in `.sops.yaml`.

## The two stores

| Store | What | Why |
|---|---|---|
| `agentik-os/omega-vault` (PRIVATE) | SSOT superset: `projects/<name>/vault/` + `core/vault/` | ONE clone recovers EVERYTHING. Holds partner-owned / no-remote / orphan / central `~/.omega` secrets. |
| in-repo `vault/` (operator-owned PRIVATE repos) | that project's own secrets, mirrored | a project clone is self-sufficient |

## Tools (`bin/`, pure bash + sops + age — no node/bun/python on the recovery path)

- `vault-add.sh <src> <vault_dir> <restore_path> [name]` — encrypt one file in, append MANIFEST,
  prove the roundtrip (KV map for dotenv/json, byte for binary), gate on `sops filestatus`.
- `vault-verify.sh <vault_dir>` — adversarial re-check: every file encrypted + decrypts + no leak.
- `vault-restore.sh [--dry-run] [vault_dir]` — **the recovery button.** Reads `MANIFEST.tsv`,
  `sops -d` every entry back to its real path, chmod 600.
- `vault-lib.sh` — shared helpers (format routing, filestatus gate, KV metric).

## Format routing (council-verified at runtime — do NOT assume dotenv everywhere)

- plain `KEY=VALUE` `.env` → **sops dotenv**
- multiline / PEM / JWT / inline-JSON value → **binary** (sops dotenv HARD-FAILS on multiline:
  `invalid dotenv input line`)
- `.json` → **json** (note: encrypts ALL string values, incl. non-secret names)
- `.toml` / `*.git-credentials` / `npmrc` / `.sh` / `.pem` → **binary** (no native TOML/INI type)

## Proof is runtime, not vibes (L1)

- A dotenv roundtrip is **NOT byte-identical** (comments become encrypted blobs, blank lines drop,
  empty values stay plaintext) — verify the **parsed KEY=VALUE map**, never `cmp`/sha the file.
- `gitleaks` scans SOPS ciphertext **CLEAN** — it is NOT the encryption proof. The proof is
  `sops filestatus <f>` == `{"encrypted":true}`.
- `sops -d` inherits umask (0644) — restore **chmods 0600** (git-credentials, npmrc especially).

## Custody (the one thing to guard)

The single master key honors the "one key" goal but is a total-compromise single point. Its backup
is **MANDATORY and TEST-verified**: operator **password manager** + an **OFFLINE** copy (paper/steel/
USB in a safe), stored beside the **GitHub 2FA recovery codes** and a **bootstrap clone token that
lives OUTSIDE omega-vault** (else recovery cannot bootstrap). **NEVER** put the master key in GitHub
Actions (that recouples key + ciphertext) — mint a scoped CI recipient if CI ever needs decrypt,
never the master. See `RECOVERY.md`.

## Incident policy (a plaintext secret already pushed)

Rotation is the **default** remediation: rotate the live credential → untrack + placeholder-scrub →
history-rewrite **only on operator sign-off** (force-push is R-COUNCIL). Ciphertext-in-history and
pushed-plaintext-in-history are both readable forever; master-key rotation does **not** remediate a
leaked value — only rotating the value does. Keep the vault in sync on every rotation (a stale vault
silently restores a dead key).

## v2 hardening (recorded, council dissent)

Passphrase-wrap (`age -p`) or yubikey-back the at-rest identity; split a recovery key (PM/offline
only) from per-project operational recipients for real cryptographic R-PROJ blast-radius containment.
`vault-lib.sh` already supports multiple recipients via `VAULT_RECIPIENT`.

Files in this skill

  • RECOVERY.md3.7 KB
  • SKILL.md5.1 KB
  • bin/vault-add.sh2.3 KB
  • bin/vault-lib.sh4.2 KB
  • bin/vault-restore.sh1.6 KB
  • bin/vault-verify.sh1.8 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…