docs: add managed scope admin guide + cross-link from configuration

This commit is contained in:
Ben 2026-06-18 14:20:06 +10:00 committed by Teknium
parent ddd519ea70
commit 9a24e41d0f
3 changed files with 164 additions and 0 deletions

View file

@ -59,6 +59,12 @@ Settings are resolved in this order (highest priority first):
Secrets (API keys, bot tokens, passwords) go in `.env`. Everything else (model, terminal backend, compression settings, memory limits, toolsets) goes in `config.yaml`. When both are set, `config.yaml` wins for non-secret settings.
:::
:::tip Org deployments
An administrator can pin specific config and secret values that a standard user
cannot override, via a system-level managed directory. See
[Managed Scope](/user-guide/managed-scope).
:::
## Environment Variable Substitution
You can reference environment variables in `config.yaml` using `${VAR_NAME}` syntax:

View file

@ -0,0 +1,157 @@
---
sidebar_position: 3
title: "Managed Scope"
description: "Administrator-pinned, user-immutable config and secrets via a system-level managed directory"
---
# Managed Scope
**Managed scope** lets an administrator push a baseline of configuration and
secrets that a standard (non-root) user **cannot override**. It is intended for
fleet/org deployments where IT needs to pin, for example, the model provider, a
shared API base URL, or `security.redact_secrets: true` across every user on a
machine.
When a managed scope is present, the values it specifies win over the user's
`~/.hermes/config.yaml`, `~/.hermes/.env`, and even the shell environment — for
exactly the keys it pins. Everything else stays fully user-controlled.
:::note Different from a package-managerlocked install
A package-managermanaged install (declarative-distro / formula) blocks *all*
config mutation and tells you to use your package manager. Managed scope is a
separate mechanism: it injects *specific immutable values* on a per-key basis
rather than locking the whole config. The two are independent and can coexist.
:::
## Where it lives
Managed scope is read from a system-level directory, default `/etc/hermes`:
```text
/etc/hermes/
├── config.yaml # managed config layer (wins over ~/.hermes/config.yaml)
└── .env # managed env layer (wins over ~/.hermes/.env + shell)
```
The directory and files are owned by `root` (directory mode `0755`, files
`0644`): readable by everyone, writable only by an administrator. **That
filesystem permission is the enforcement mechanism** — a standard user can read
the managed files but cannot edit them.
Either file is optional. A missing managed directory or missing file simply
means "no managed scope," and configuration resolves exactly as it does without
the feature.
### Relocating the directory
The location can be relocated with the `HERMES_MANAGED_DIR` environment variable
(for containers or non-`/etc` deployments). This is a deployment/bootstrap path
knob — like `HERMES_HOME` — set by the same administrator who owns the managed
files. It is **never persisted** to any `.env` by Hermes.
```bash
# Point managed scope at a custom directory (set by IT / the deployment, not the user)
export HERMES_MANAGED_DIR=/opt/org/hermes-policy
```
:::warning
A user who can set `HERMES_MANAGED_DIR` can repoint managed scope at a directory
they control, defeating it. In a real deployment this variable should be fixed
by the administrator (e.g. baked into the service unit / container image), not
left user-settable. `hermes doctor` reports the *resolved* managed directory so
a redirect is visible.
:::
## Precedence
For the keys a managed layer specifies, the order is (highest wins):
| Tier | config.yaml | .env |
|---|---|---|
| 1 | `/etc/hermes/config.yaml` (managed) | `/etc/hermes/.env` (managed) |
| 2 | `~/.hermes/config.yaml` (user) | `~/.hermes/.env` (user) |
| 3 | built-in defaults | pre-existing shell environment |
Merging is **leaf-level**: pinning `model.default` does not freeze the rest of
`model.*`. A managed `config.yaml` of:
```yaml
model:
default: org/standard-model
```
forces `model.default` for every user while leaving `model.fallback` (and every
other key) under user control.
:::note Precedence note
For the keys it pins, managed scope deliberately wins over the shell environment
too — otherwise it would not be "managed." This is the one place that inverts the
usual "an environment variable overrides config.yaml" rule, and it applies only
to the specific keys the managed layer specifies.
:::
## Seeing what's managed
```bash
hermes config # shows a header naming the managed source + the pinned keys
hermes doctor # reports the resolved managed dir + pinned key counts
```
If you try to change a managed value, Hermes refuses and names the source:
```bash
$ hermes config set model.default my/model
Cannot set 'model.default': it is managed by your administrator
(/etc/hermes/config.yaml) and cannot be changed.
```
The same applies to managed secrets — `hermes config set` / setup will not write
a user value for an env key pinned by the managed `.env`.
## Setting up a managed scope (administrators)
```bash
sudo mkdir -p /etc/hermes
# Pin some config values for every user on this machine
sudo tee /etc/hermes/config.yaml >/dev/null <<'YAML'
model:
provider: nous
security:
redact_secrets: true
YAML
# Optionally pin a shared, non-sensitive env value
sudo tee /etc/hermes/.env >/dev/null <<'ENV'
OPENAI_API_BASE=https://inference.example.com/v1
ENV
sudo chmod 0755 /etc/hermes
sudo chmod 0644 /etc/hermes/config.yaml /etc/hermes/.env
```
Changes take effect on the next Hermes start (a malformed managed file is logged
loudly and ignored — it never blocks startup, but the admin should check
`hermes doctor` to confirm the policy is being applied).
## Security model and limitations (v1)
- **Enforcement is filesystem permissions only.** If a user has write access to
the managed directory (or runs Hermes as `root`), managed scope is advisory.
- **The managed `.env` is world-readable** (`0644`), so any local user can read
secrets pushed through it. Use it for shared, non-sensitive values (an org API
base URL, feature defaults) rather than high-sensitivity secrets.
- **The agent's own tools are not hard-blocked from a managed *env* value.** A
managed environment variable is applied at startup, but nothing stops the
agent from setting a different value inside its own subprocess shell. v1 is a
management-convenience boundary against a normal user, not an un-escapable
sandbox.
The following are intentionally **out of scope for v1** and may come later:
- A hard boundary that the agent itself cannot escape.
- Native managed locations on macOS and Windows (v1 is Linux/POSIX-first).
- Drop-in fragment directories (`managed.d/`) for layered policy.
- Signed / integrity-checked managed files.
- Remote / device-management (MDM) delivery.
- Tighter (group-scoped) permissions for managed secrets.

View file

@ -27,6 +27,7 @@ const sidebars: SidebarsConfig = {
'user-guide/windows-native',
'user-guide/windows-wsl-quickstart',
'user-guide/configuration',
'user-guide/managed-scope',
'user-guide/configuring-models',
{
type: 'category',