Files
dtoro 4560e25bd7 hermes-agent: onboard Nous-Hermes-on-Goose to homelab clients
`bootstrap.sh --with-hermes` installs the Goose CLI, drops a Goose
config pinning the OpenRouter provider + Nous Hermes model + the
homelab MCP extension, symlinks `bin/hermes` and HERMES.md, and links
HERMES.md as `.goosehints` so the persona is injected as the system
prompt every session.

`bin/hermes` decrypts `secrets/openrouter-api-key.yaml` via the existing
`homelab secret` flow and execs `goose session`.

`homelab client add --with-hermes` grants the new sops secret to the
host's age_pubkey at finalize time (parallel to the existing
shared-secrets grant). `client remove` revokes it.

`operations/hermes-agent.md` covers the end-to-end flow, verification,
troubleshooting, and queues one follow-up: the MCP server still runs
SSE-only but Goose 1.x deprecated SSE — the Goose config targets
`streamable_http` and the `homelab` extension won't connect until
`mcp/server.py` migrates. The `developer` extension (shell + edit +
`homelab` CLI) carries the agent in the meantime.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-31 01:18:43 +02:00
..
2026-05-20 19:29:47 +02:00
2026-05-20 19:29:47 +02:00

secrets/

SOPS-encrypted YAML files. The plaintext lives only in transit and in the operator's head — committed files are always ciphertext.

Conventions

  • One file per logical grouping (e.g. gitea-tokens.yaml, webhook-hmacs.yaml, api-keys.yaml).
  • Recipients are declared in ../.sops.yaml by path-regex, not per-file.
  • The plaintext schema inside each file is free-form YAML; the consumer code decides what it expects (e.g. gitea-tokens.yaml contains {"<host>": "ghp_xxx"}).

How to add a secret

# 1. Decide which clients should be able to decrypt it; edit ../.sops.yaml to
#    list their age public keys for the new path_regex.
# 2. Create the plaintext, encrypt in place:
sops -e --in-place secrets/my-thing.yaml
# 3. Commit + push. The 5-min sync propagates to every recipient.

How to consume a secret

# On any client that's a recipient:
homelab secret my-thing               # prints plaintext
# Or programmatically:
sops -d /opt/homelab-context/secrets/my-thing.yaml

The mcp tool list_my_secrets(caller_pubkey) returns the names of secrets the caller can decrypt. The MCP server never reads plaintext — decryption stays client-side.

Granting / revoking access

To grant a new recipient: edit ../.sops.yaml to add their age pubkey, then re-key every affected file:

sops updatekeys -y secrets/my-thing.yaml

To revoke: remove the recipient from ../.sops.yaml and sops updatekeys — but remember this only protects future ciphertext. Past plaintext the client already decrypted is gone from your control. Rotate the underlying credential if compromise is suspected.

homelab client remove <name> does the recipient removal + updatekeys for you, and prints the rotation checklist as a follow-up.

hello.yaml — bootstrap decrypt test

secrets/hello.yaml is encrypted to every enrolled client. Used by Phase 3a verification to confirm the end-to-end decrypt path works on a freshly- bootstrapped machine. Content is intentionally trivial:

greeting: hello from the homelab