Resolves environment variables from an Infisical
secret store (US/EU cloud or self-hosted) at Hermes startup, so provider
credentials never live in plaintext in ~/.hermes/.env.
Registers two secret sources:
| Source | Shape | Purpose |
|---|---|---|
infisical |
mapped | Bind env vars to explicit inf:// references (wins conflicts) |
infisical_bulk |
bulk | Inject a whole project/environment/folder (yields conflicts) |
The plugin is strictly read-only and runs only at process startup, per the Hermes secret-source contract.
- Hermes Agent with secret-source plugin support (API version 1).
- An Infisical server exposing the v4 secrets API (Infisical Cloud, or a recent self-hosted release).
- No extra Python packages: the plugin uses
requests, which Hermes ships.
git clone <this-repo> ~/.hermes/plugins/infisicalThen enable plugins and the sources in your Hermes config.
plugins:
enabled: [infisical]
secrets:
sources: [infisical, infisical_bulk]
infisical:
enabled: true # master switch
host_url: https://us.infisical.com # or EU / self-hosted URL
organization: "" # optional org ID, validation only
timeout_seconds: 120 # wall-clock fetch budget
override_existing: true # mapped bindings beat .env values
auth:
method: agent # agent | universal-auth | token
agent_token_path: ~/.infisical/agent-token
# for method: universal-auth —
client_id_path: /etc/infisical/client-id
client_secret_path: /etc/infisical/client-secret
env:
OPENAI_API_KEY: inf://my-project/prod/backend/OPENAI_API_KEY
DB_PASSWORD: inf://my-project/prod/db/pg-creds?type=dynamic&field=password&ttl=8h
infisical_bulk:
enabled: true
host_url: https://us.infisical.com
organization: ""
timeout_seconds: 120
override_existing: false # bulk yields to everything else
auth:
method: agent
agent_token_path: ~/.infisical/agent-token
project: my-project # name, slug, or project ID
environment: prod # environment slug
secret_path: /backend # folder to inject from
recursive: false # include nested folders
include_imports: true # include imported secretsUse YAML anchors to share the auth/host_url block between the two
sections.
inf://<project>/<environment>[/<folder>...]/<key>[?options]
<project>— project name, slug, or ID. Names/slugs are resolved via the API once per process; IDs skip that call. Percent-encode spaces in display names (My%20Project).<environment>— environment slug (dev,staging,prod, …).- Folders are optional; without them the key is read from
/. - Options:
type=dynamic(create a dynamic-secret lease),field=<name>(which field of the generated credentials to inject — required when the payload has more than one),ttl=<duration>(lease TTL, e.g.8h).
agent(default): reads the access token the local Infisical Agent writes to its file sink. Pointagent_token_pathat thepathyou configured undersinks:in the agent's config.universal-auth: a Machine Identity client ID/secret, taken from theINFISICAL_CLIENT_ID/INFISICAL_CLIENT_SECRETenv vars or from the files named byclient_id_path/client_secret_path. The plugin logs in at startup and holds the short-lived token in memory only.token: a static access token from theINFISICAL_TOKENenv var.
INFISICAL_TOKEN, INFISICAL_CLIENT_ID and INFISICAL_CLIENT_SECRET are
protected: no secret source (including this one) may overwrite them.
- Dynamic-secret leases are created once, at startup. The Hermes
contract has no runtime hook, so leases are never renewed — choose a
ttlthat outlives your agent session. - No write-back. Reading only; creating or updating secrets is out of scope by design.
- The v4 list endpoint returns a folder in one response (no pagination); very large folders are bounded by the fetch timeout budget.
- Install the plugin (above) and enable it in the Hermes config.
- Create an Infisical project with a test secret, e.g.
prod→/backend/HERMES_E2E_CHECK. - Configure one auth method (start the Infisical Agent, or export
INFISICAL_CLIENT_ID/INFISICAL_CLIENT_SECRET). - Map it:
env: {HERMES_E2E_CHECK: inf://<project>/prod/backend/HERMES_E2E_CHECK}. - Start Hermes with
HERMES_PLUGINS_DEBUG=1and confirm the plugin loads andHERMES_E2E_CHECKis present in the agent's environment. - Break the token on purpose and confirm startup continues with a clear
one-line
infisical: auth_failed: ...warning.
scripts/fetch-hermes.sh # pinned hermes-agent checkout into .deps/
pip install -r requirements-dev.txt
python -m pytest tests/ --cov=infisical_plugin --cov-fail-under=80Error messages follow one shape everywhere:
infisical: <error_kind>: <actionable message> — and never contain secret
values or tokens.