Skip to content

Commit b762781

Browse files
committed
docs: explain optional HMAC secret
1 parent c4c6e4b commit b762781

2 files changed

Lines changed: 40 additions & 13 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ uses [Semantic Versioning](https://semver.org/).
99

1010
- Restored a visible README overview of Olla, oMLX, llama.cpp, Ollama, and
1111
LiteLLM compatibility while retaining the detailed compatibility guide.
12+
- Clarified that `sha256` needs no additional secret, explained what the HMAC
13+
secret protects, and separated the optional HMAC setup from the basic quick
14+
start.
1215

1316
## [0.3.0] - 2026-07-15
1417

README.md

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,19 @@ Install and enable the plugin:
2121
hermes plugins install shared-goals/hermes-custom-header-plugin --enable
2222
```
2323

24-
Generate a secret containing at least 32 bytes and store it in
25-
`~/.hermes/.env` as `HERMES_CUSTOM_HEADER_HMAC_KEY`:
24+
First choose how the routing value should be derived:
2625

27-
```bash
28-
python -c 'import secrets; print(secrets.token_urlsafe(32))'
29-
```
26+
| Strategy | Additional secret | When to use it |
27+
| --- | --- | --- |
28+
| `sha256` | Not required | You only need a stable routing key and accept that guessed inputs can be verified against an observed header. |
29+
| `hmac-sha256` | Required | The header may be observed and you want to prevent offline guessing or reproduction without an installation-local secret. |
30+
31+
Both strategies provide the same sticky-routing behavior. The secret does not
32+
authenticate with the provider, is never sent to Thunder Forge or Olla, and
33+
does not by itself improve routing or KV-cache performance.
3034

31-
Add a named provider and an exact plugin rule to `~/.hermes/config.yaml`:
35+
The simplest setup uses `sha256` and needs no additional secret. Add a named
36+
provider and an exact plugin rule to `~/.hermes/config.yaml`:
3237

3338
```yaml
3439
providers:
@@ -45,7 +50,7 @@ plugins:
4550
custom:thunder-forge:
4651
headers:
4752
X-Olla-Session-ID:
48-
strategy: hmac-sha256
53+
strategy: sha256
4954
namespace: installation-a
5055
inputs:
5156
- session_id
@@ -54,6 +59,24 @@ plugins:
5459
digest_length: 32
5560
```
5661
62+
To protect the generated value from offline input guessing, generate at least
63+
32 random bytes:
64+
65+
```bash
66+
python -c 'import secrets; print(secrets.token_urlsafe(32))'
67+
```
68+
69+
Store the output only on the Hermes installation:
70+
71+
```dotenv
72+
HERMES_CUSTOM_HEADER_HMAC_KEY=<generated value>
73+
```
74+
75+
Then change the rule to `strategy: hmac-sha256`. Olla does not need this secret;
76+
it still receives only the generated routing value. Changing strategy or
77+
rotating the secret changes all routing keys, so existing conversations will
78+
produce an initial sticky miss before becoming pinned again.
79+
5780
Restart long-running Hermes processes after configuration changes:
5881

5982
```bash
@@ -72,12 +95,13 @@ from Hermes' request context and fails closed for that endpoint.
7295

7396
Supported strategies:
7497

75-
- `hmac-sha256` is recommended. It derives an opaque value using
76-
`HERMES_CUSTOM_HEADER_HMAC_KEY`, a required non-secret namespace, and the
77-
configured runtime inputs. The key is never emitted or logged.
78-
- `sha256` remains available for legacy routing compatibility. It is an
79-
unkeyed deterministic pseudonym, not privacy protection; anyone who can guess
80-
the inputs can verify guesses offline.
98+
- `sha256` derives an unkeyed deterministic pseudonym and requires no secret.
99+
It is sufficient for stable routing, but it is not privacy protection: anyone
100+
who can guess the inputs can verify guesses against an observed header.
101+
- `hmac-sha256` derives the same kind of stable routing value using
102+
`HERMES_CUSTOM_HEADER_HMAC_KEY` as a key. It prevents verification or
103+
reproduction without the installation-local secret. The key is never emitted
104+
or logged and is unrelated to provider authentication.
81105

82106
For `namespace: installation-a` and `inputs: [session_id, model]`, the payload
83107
is `installation-a + NUL + session_id + NUL + model`. Runtime values containing

0 commit comments

Comments
 (0)