Localsetup localsetup-keepass-secrets
Resolve logical secret IDs through KeePass using repo-local mapping files; optionally bulk-create or rotate secrets without ever writing values into tracked files.
git clone https://github.com/CruxExperts/localsetup
T=$(mktemp -d) && git clone --depth=1 https://github.com/CruxExperts/localsetup "$T" && mkdir -p ~/.claude/skills && cp -r "$T/_localsetup/skills/localsetup-keepass-secrets" ~/.claude/skills/cruxexperts-localsetup-localsetup-keepass-secrets && rm -rf "$T"
_localsetup/skills/localsetup-keepass-secrets/SKILL.mdKeePass-backed secrets (localsetup-keepass-secrets)
Purpose
Provide a safe way for agents and tools to look up and (optionally) create or rotate infrastructure secrets using a KeePass database as the canonical store, while keeping all secret values out of repository files. The skill works with logical secret IDs and repo-local mapping files, then delegates to a
.keepass_secrets/ helper and keepassxc-cli for the actual secret operations.
When to use this skill
- User asks for logins, API keys, or service accounts that already live in KeePass (for example, "give me the login for admin@cruxexperts.com").
- A workflow needs DB credentials or mailboxes for a specific host (for example,
,mail.box03.cruxexperts.admin
), and those entries are already mapped intopostgres.box03.app1
.secrets/*-secrets-map.yaml - You want to bulk-create or rotate accounts (hundreds at a time) with strong random passwords, but you must not paste those passwords into docs or config files.
- You need a stable logical ID for documentation and workflows so you can reference secrets without re-embedding their values.
Inputs and logical model
Logical IDs and service types
- Logical IDs follow
form, for example:service.host.scope.namemail.box03.cruxexperts.adminmail.box03.cruxexperts.infominio.box03.rootpostgres.box03.app1api.box03.stripe.live
- Canonical
values:service_typemail.mailboxdb.userapi.keyservice.accountssh.key
- Normalized secret fields:
,idservice_type
,username
,password
,token
,urlnotes
: dict with service-specific details (for examplemeta
,domain
,database
,env
,role
,host
).port
Repo-local configuration and mapping
-
:secrets/keepass-config.yaml-
Holds non-secret metadata about KeePass databases.
-
Example:
default_database: "secrets/infra.kdbx" databases: infra: path: "secrets/infra.kdbx" keyfile: null # must point outside the repo when used password_source: "prompt" bootstrap: created_at: null created_by: null
-
-
(for examplesecrets/<host>-secrets-map.yaml
):secrets/box03-secrets-map.yaml-
Maps logical IDs to KeePass entry paths and optional metadata, with no secret values:
database: "infra" entries: mail: box03: cruxexperts: admin: service_type: "mail.mailbox" path: "Servers/box03/Mail/admin@cruxexperts.com" username: "admin@cruxexperts.com" info: service_type: "mail.mailbox" path: "Servers/box03/Mail/info@cruxexperts.com" username: "info@cruxexperts.com" minio: box03: root: service_type: "service.account" path: "Servers/box03/MinIO/root" aliases: mail-address: "admin@cruxexperts.com": "mail.box03.cruxexperts.admin" "info@cruxexperts.com": "mail.box03.cruxexperts.info"
-
-
Mapping files are treated as read-only by helpers: agents and CLIs never rewrite them; humans edit them via normal code review.
Interfaces exposed by this skill
This skill does not expose a Python API directly; instead it describes how agents should invoke the underlying helper CLIs.
get_secret(id, fields=None, host=None)
-
Inputs:
:id- Logical secret ID (
) or an alias such as an email address.service.host.scope.name
- Logical secret ID (
:fields- Optional list (or comma-separated string) of fields to return.
- Supported field names:
,username
,password
,url
,notes
,meta
.service_type
:host- Optional host name (for example
).box03 - If omitted, host is resolved in this order:
- CLI
argument, if provided by the caller.--host
environment variable, if set.LOCALSETUP_HOST- Single
file under*-secrets-map.yaml
(auto-selected).secrets/ - Otherwise, fail with an "ambiguous host, please specify --host" error.
- CLI
- Optional host name (for example
-
Behavior:
-
Resolve repo root by walking up from
untilcwd
is found._localsetup/ -
Load
(or apply a safe default if absent).secrets/keepass-config.yaml -
Load the appropriate host map from
.secrets/<host>-secrets-map.yaml -
Resolve aliases (for example, mail address to logical ID).
-
Map the logical ID into:
- KeePass database path (from
).keepass-config.yaml - KeePass entry path (from the host mapping file).
- Optional
andservice_type
.expected_username
- KeePass database path (from
-
Shell out to:
python -m keepass_secrets.cli_get --id "<ID_OR_ALIAS>" [--host <host>] [--fields ...] [--human] -
:keepass-secrets-get- Checks that
is installed and at least at the required version; if not, fails fast with a clear message and installation/upgrade hint.keepassxc-cli - Uses
to retrieve the entry.keepassxc-cli show --format json - Maps KeePass fields (
,UserName
,Password
,URL
, and others) into aNotes
.SecretRecord - Optionally merges mapping metadata (for example,
, expectedservice_type
).username - Returns a JSON object on stdout with the requested fields only.
- Checks that
-
-
Outputs:
- JSON object with:
: resolved logical ID.id- Optional
,service_type
,username
,password
,token
,url
,notes
.meta
- When
is passed, the CLI prints a short human-readable summary instead of JSON, but still does not write secrets to any file.--human
- JSON object with:
ensure_secrets(batch_spec_path, host=None, force=False, dry_run=False)
-
Inputs:
-
:batch_spec_path-
Path to a YAML batch spec describing many logical IDs and desired parameters.
-
Example:
host: box03 items: - id: mail.box03.cruxexperts.admin service: mail.mailbox username: "admin@cruxexperts.com" generate_password: true rotate_password: false - id: mail.box03.cruxexperts.info service: mail.mailbox username: "info@cruxexperts.com" generate_password: true
-
-
:host- Optional override for
, resolved via the same precedence rules asspec.host
.get_secret
- Optional override for
-
:force- If
, mismatches between existing KeePass usernames and mapping spec cause a failure with a clear error.false - If
, allows updating usernames and similar fields in KeePass to match the mapping/batch spec.true
- If
-
:dry_run- When
, validates mappings, existence, and diffs but does not write any changes to KeePass.true
- When
-
-
Behavior:
-
Parse the batch spec (must contain a non-empty list of
).items -
For each item:
- Resolve the logical ID into KeePass DB path and entry path using the host map and
.keepass-config.yaml - Determine
:username- Prefer
, else mappingitem.username
, else fail.username
- Prefer
- Probe for existing entries using
:keepassxc-cli show- If entry exists and has a password:
- When
isrotate_password
andfalse
isgenerate_password
, treat as reused and do not change it.false - When
isrotate_password
ortrue
is true and no password is present, generate a new password and write it.generate_password
- When
- If entry does not exist:
- Generate a password when
is true; otherwise fail clearly.generate_password
- Generate a password when
- If entry exists and has a password:
- On username mismatch (existing KeePass vs mapping) and
not set, fail with a descriptive error instead of changing the entry.force - When not in
, calldry_run
to create or update the entry.kp_write_entry
- Resolve the logical ID into KeePass DB path and entry path using the host map and
-
Shell out to:
python -m keepass_secrets.cli_ensure --spec batch.yaml [--host <host>] [--force] [--dry-run]
-
-
Outputs:
- JSON summary on stdout with:
: list ofcreated
for entries newly created.{id, path}
: list ofreused
for entries that already existed and were left unchanged.{id, path}
: list ofrotated
for entries whose passwords were rotated.{id, path}
: list oferrors
descriptions; callers should fail the overall operation when this is non-empty.{id, path?, error}
- No passwords or tokens are written to mapping files, only to KeePass and to the ephemeral JSON output of the run.
- JSON summary on stdout with:
Security and safety rules
- Secrets:
- Secret values (passwords, tokens, key material) live only in:
- KeePass
databases..kdbx - Ephemeral CLI stdout and in-memory structures for the current call.
- KeePass
- Never write secret values into:
- Tracked repository files (YAML, markdown, code).
- Logs, telemetry, or long-lived artifacts.
- Secret values (passwords, tokens, key material) live only in:
- KeePass databases and keys:
- KeePass DB files such as
may be versioned in some repos, but master passwords and keyfiles must be kept outside the repo.secrets/infra.kdbx
may reference keyfiles and password sources, but must never contain cleartext secrets.keepass-config.yaml
- KeePass DB files such as
- Error handling:
- Error messages must not contain KeePass
output or any secret field values.show - Errors may refer to logical IDs, hosts, KeePass entry paths, and high-level failure reasons only.
- Error messages must not contain KeePass
- Mapping files:
andkeepass-config.yaml
are safe to track in git because they contain no secrets.*-secrets-map.yaml- CLIs and agents treat these files as read-only; only humans edit them.
- Input hardening:
- Logical IDs, host names, and paths are validated against safe patterns before being interpolated into shell commands.
- Invalid IDs or suspicious characters cause immediate failures rather than being passed to
.keepassxc-cli
Bootstrap and installation behavior
KeePass CLI availability and installation hints
- On every read/write operation, the helper checks
:keepassxc-cli- If the binary is missing:
- Fail fast with a clear message:
keepassxc-cli is not installed or not on PATH. Install KeePassXC (including the CLI) from your package manager and ensure keepassxc-cli is available. - Optionally add repo-local docs with distro-specific commands and point to them from this error.
- Fail fast with a clear message:
- If the version is older than the configured minimum (for example
):2.7.0- Fail fast with a message like
keepassxc-cli version X.Y.Z is too old. Install at least 2.7.0.
- Fail fast with a message like
- The skill does not try to run package managers by itself; it only proposes installation or upgrade steps for a human to run.
- If the binary is missing:
Config and database bootstrap
- Missing
:secrets/keepass-config.yaml- CLIs and this skill:
- Print a short error explaining that
is required.secrets/keepass-config.yaml - Show a minimal template the user can copy into
.secrets/keepass-config.yaml - Exit non-zero; they never create the file automatically.
- Print a short error explaining that
- CLIs and this skill:
- Missing or invalid DB path:
- If the configured DB path does not exist:
- Explain that a KeePass DB is required and that the user must either:
- Point
at an existingkeepass-config.yaml
, or.kdbx - Create a new DB manually via KeePassXC UI or
.keepassxc-cli db-create
- Point
- Do not auto-create the DB or generate master passwords.
- Explain that a KeePass DB is required and that the user must either:
- KDF settings:
- When humans create a new DB they should configure Argon2id with:
- Memory cost on the order of 128–256 MiB.
- Time cost tuned for around 2–3 seconds on the current host.
- Parallelism of 2–4.
- This tuning is done once at DB creation time, not on each secret operation.
- When humans create a new DB they should configure Argon2id with:
- If the configured DB path does not exist:
- Missing host mapping file:
- When the requested host map
is missing:secrets/<host>-secrets-map.yaml- CLIs and this skill emit a clear error naming the missing file.
- They refuse to proceed until the mapping file exists and passes basic validation.
- When the requested host map
Interaction constraints and platform support
- Interactivity:
- For v1, both helper CLIs expect an interactive TTY:
- They rely on
to prompt for master passwords when required.keepassxc-cli - If stdin is not a TTY (for example in CI), they fail fast with a clear message instead of hanging.
- They rely on
- Non-interactive modes (for example env-var based master passwords) are a future, opt-in extension and must be carefully documented.
- For v1, both helper CLIs expect an interactive TTY:
- Supported platforms:
- v1 is scoped to Linux hosts where
is installed and on PATH.keepassxc-cli - On unsupported platforms (for example when
is clearly non-Linux), helpers should fail fast with a short explanation.sys.platform
- v1 is scoped to Linux hosts where
Documentation and usage patterns
- Secrets overview:
- Repositories that adopt this skill should add a short doc (for example
) that:docs/local-context/SECRETS_OVERVIEW.md- States that secrets live in KeePass, not in repo files.
- Mentions
andsecrets/keepass-config.yaml
as the mapping layer.secrets/*-secrets-map.yaml - Shows how to reference secrets by logical ID in docs instead of pasting values.
- Repositories that adopt this skill should add a short doc (for example
- Referencing in docs:
- In context docs, prefer patterns like:
Secret ID: mail.box03.cruxexperts.adminSecret ID: postgres.box03.app1
- When a human needs the credentials, they run a workflow that calls this skill with that ID and shows the result interactively.
- In context docs, prefer patterns like:
- Login-card helpers:
- Higher-level workflows can build convenience helpers (for example "show login for admin@cruxexperts.com") by:
- Mapping an email address to a logical ID via
in the host map.aliases - Calling
through this skill.get_secret(id) - Presenting host, username, and password in the chat only, never committing them to disk.
- Mapping an email address to a logical ID via
- Higher-level workflows can build convenience helpers (for example "show login for admin@cruxexperts.com") by: