Watch
0
0
Fork
You've already forked hyperhive
0
hyperhive/docs/turn-loop/config.md

313 lines
14 KiB
Markdown

# Agent config knobs
Optional per-agent knobs, set under `services.hyperhive.agent.*` in the
agent's own `agent.nix` and read at boot or per turn by the harness.
Absent means the default. (The claude spawn + compaction themselves live in
[claude-invocation](claude-invocation.md).)
## Reference docs (`services.hyperhive.agent.docs.enable`)
```nix
services.hyperhive.agent.docs.enable = true; # default: false
```
Makes the hyperhive `docs/` tree available inside the container at a nix
store path read from `$HIVE_DOCS_DIR`, and injects a single pointer
sentence into the agent's system prompt so it knows the docs exist and
where to find them. `claude --add-dir` serves the tree so the full
markdown is readable during every turn.
Off by default for every agent, ruth included. An agent opts in by adding the
line above to its `agent.nix`.
The docs come from the pinned `hyperhive` input (the `reference-docs` package
built from its `docs/` tree), so they match the hyperhive rev the host runs.
## Agent icon
```nix
services.hyperhive.agent.icon = ./icon.svg; # default: null (falls back to shared hyperhive logo)
```
Path to an SVG file used as this agent's visual identity — shown in
the per-agent page header, as the page favicon, and uploaded to the
agent's Forgejo profile avatar (via the `forge-avatar-sync` boot
unit) and Matrix profile avatar (set by `hive-matrix-daemon` over its
live Client). Commit the SVG next to `agent.nix` in the config repo
and reference it as a relative path.
When `null` (the default), the agent falls back to the shared
hyperhive branding mark. The harness serves whichever icon is active
at `GET /icon` on the per-agent web port.
## `user.passwordlessSudo`
```nix
services.hyperhive.agent.user.passwordlessSudo = true; # default
```
Grants the per-agent unix user passwordless `sudo` (`NOPASSWD: ALL`).
Enabled by default so claude's shell tools work for operations that
need root inside the container (`systemctl`, package managers in dev
shells, etc.) — the agent user gets root explicitly via `sudo` rather
than running as root itself.
Set to `false` for agents that should be strictly unprivileged.
Any tool invocation that needs root then fails loudly with the standard
sudo rejection rather than silently succeeding — easier to audit.
`services.hyperhive.agent.user.name` is the unix user the harness and
its co-process daemons run as inside the container (default `"agent"`
for a standalone evaluation; the meta flake rebinds it to the agent's
own name). `services.hyperhive.agent.user.uid` / `.gid` are optional
fixed UID/GID (`null` default lets NixOS assign one automatically from
the normal-user range) — set them only when something outside the
container needs a stable numeric id across a full destroy + recreate.
## Dashboard links
```nix
services.hyperhive.agent.dashboardLinks = [
{ label = "Stats"; icon = "📊"; url = "http://localhost:9001/stats"; }
{ label = "Scratchpad"; url = "http://localhost:8080"; }
];
```
Declares extra navigation links that appear in the per-agent page
header alongside the built-in forge / config / container links. Each
entry has:
| Field | Required | Description |
| ------- | -------- | ----------------------------------------------------------------------------------------- |
| `label` | yes | Display text shown in the icon strip tooltip and meta-nav. |
| `url` | yes | Absolute URL — may include a different port (the dashboard renders it as a plain anchor). |
| `icon` | no | Emoji or short glyph prefix. Defaults to empty string. |
A one-shot systemd unit writes the list to
`<state>/hyperhive-dashboard-links.json` at container boot. The harness's own web UI
(`agent_links` in `hive-agent/src/web_ui/state.rs`) reads the file on
each `/api/state` snapshot and appends the entries to the per-agent
nav as `kind = External` links — no `hive-c0re` / operator-dashboard
involvement, and no code change needed to pick up a new entry.
Omitting the option (default empty) produces no extra links.
## Custom static files
```nix
services.hyperhive.agent.frontend.extraFiles = {
"games/bitburner" = {
source = ./bitburner-dist; # path relative to agent.nix
# target defaults to attribute name: "games/bitburner"
};
"my-page" = {
source = ./my-page.html;
target = "my-page.html"; # explicit override
};
};
```
Layers additional files over the default per-agent web UI dist. Each
attribute defines one overlay entry:
- **`source`** — a Nix path (file or directory) copied into the merged
static tree. Evaluated at nix build time; the resulting derivation is
pointed at by `HIVE_STATIC_DIR`.
- **`target`** — destination path within the merged tree, used as both
the served URL prefix (`/<target>/…`) and the on-disk layout.
Defaults to the attribute name. Forward slashes create nested layouts
(`"games/bitburner"` serves at `/games/bitburner/…`).
Constraints: `target` must start with an alphanumeric or `_` and
contain only alphanumerics, `_`, `.`, `/`, `-`. A config assertion
rejects `..` segments. The merge step refuses to overwrite
files already present in the default dist — pick a target name that
doesn't collide with existing paths (`static/`, `index.html`, etc.).
The default dist ships at `services.hyperhive.agent.frontend.dist` (the
`hyperhive-frontend` package output, read-only). To replace the
entire UI rather than layer on top, override `frontend.dist` directly.
## Connectivity overrides
Two `services.hyperhive.agent.forge.*` / `services.hyperhive.agent.matrix.*` options override where
the per-agent daemons connect. Both rarely need changing on a standard
single-host deploy, but are useful for multi-hive or custom-network
setups.
```nix
services.hyperhive.agent.forge.url = "http://forge.example:3000"; # default: null
services.hyperhive.agent.matrix.url = "https://matrix.example"; # default: null
```
**`services.hyperhive.agent.forge.url`** — base URL of the Forgejo instance. It scopes
the git credential helper to this forge and is where `forge-avatar-sync`
uploads the agent's icon. Override when the agent should connect to a
Forgejo on a different host or port (for example a swarm peer's forge).
Validated: must be an `http://` or `https://` URL, or `null`.
**Defaults to `null`, meaning "no forge" — not a guessed address.** A
loopback default would only ever be correct when the forge shares the
agent's network namespace, and inside a container `localhost` is the
agent itself, so the default was a value that built fine and then talked
to the wrong machine. With `null` the credential helper and `forge-avatar-sync`
units aren't generated at all: an absent integration rather than a
misdirected one. You don't normally set this — hive-c0re renders the
host's real forge URL into every agent, and refuses to write a meta
flake without one, so `null` only survives where nix evaluates the
agent modules outside a hive.
**`services.hyperhive.agent.matrix.url`** — homeserver URL used by
`hive-matrix-daemon` when connecting via the matrix-sdk. hive-c0re
writes it into every agent at deploy time as the gateway-routed
`chat.<swarm-domain>` URL, so isolated agents can reach the homeserver.
Override per-agent when an agent should talk to a different homeserver
— for example a remote hive's tuwunel reached over a VPN, or an
external Matrix server for a federation-only agent.
**Defaults to `null`, meaning "no matrix" — same reasoning as
`forge.url` above** (a loopback default would resolve inside the
agent's own netns to the agent itself, not the homeserver). With
`null` the daemon has no homeserver and no-ops exactly as it does
without a token. The hive only forwards `HIVE_MATRIX_URL` when it
actually has a matrix vhost to name, so `null` survives where a hive
runs no homeserver, or where nix evaluates the agent modules outside a
hive.
## Claude Code plugins
The harness installs Claude Code plugins before the serve loop opens.
Three per-agent `agent.nix` options control this:
```nix
services.hyperhive.agent.claudeMarketplaces = [ # default
"anthropics/claude-plugins-official"
"${services.hyperhive.agent.packages.claude-plugins}" # hive's own local marketplace, registered as `hyperhive`
];
services.hyperhive.agent.claudePlugins = [ # default
"skill-creator@claude-plugins-official"
"base@hyperhive"
];
services.hyperhive.agent.claudePluginsAutoUpdate = false; # default
```
- **`claudeMarketplaces`** — list of marketplace sources passed to
`claude plugin marketplace add <source>`. Defaults to Anthropic's
official marketplace plus hyperhive's own `claude-plugins` nix
package (see `nix/packages/claude-plugins.nix`) — a local-path
marketplace registered under the name `hyperhive`, so a hive-authored
skill needs no forge repo or git remote to ship. Override or extend
to add custom marketplaces. Idempotent — re-adding an existing
source is a no-op.
- **`claudePlugins`** — list of plugin specs passed to
`claude plugin install <spec>`. The harness installs each spec on
every boot, assuming `install` is idempotent; failures log a warning
but don't abort boot. Boot waits for the marketplace adds, the optional
update and the installs (serial `claude plugin` calls). The harness kills
and logs any call that hasn't exited within 2 minutes, and caps the whole
sequence at 4 minutes: after that the remaining calls fail at once with
the same warning and the web UI starts. Defaults to Anthropic's
`skill-creator` (so every
agent can author, refine, and evaluate its own skills) plus
hyperhive's own `base` plugin — skills that apply to every agent
regardless of role (currently just `state-hygiene`) — all without
any per-agent wiring.
> Both plugin lists follow ordinary NixOS list-option semantics: a
> per-agent definition **replaces** the default, it doesn't extend it.
> An agent that sets `claudePlugins` and still wants the defaults has
> to list `skill-creator@claude-plugins-official` and `base@hyperhive`
> explicitly alongside its own entries — likewise for the two default
> entries in `claudeMarketplaces`.
- **`claudePluginsAutoUpdate`** — when `true`, runs
`claude plugin marketplace update` before installing plugins to pull
the latest index. Disabled by default to keep boot times short and
plugin versions pinned.
## `cargo.shortMessages`
```nix
services.hyperhive.agent.cargo.shortMessages = true; # default
```
When enabled (the default), the harness injects a `cargo` shell
function into `/etc/hyperhive/bash-env.sh` that transparently appends
`--message-format short` to compile subcommands (`build`, `check`,
`clippy`, `test`, `run`, `doc`, `bench`, `install`, `rustc`, `fix`).
This suppresses the per-crate progress lines that flood the response
window, leaving only warnings and errors.
The function handles `+toolchain` selectors (`cargo +nightly build`)
and passes through cleanly when `--message-format` is already present.
It leaves non-compile subcommands (`new`, `add`, third-party
`cargo-*`) untouched.
Set to `false` for agents that parse cargo's JSON output
programmatically and don't pass `--message-format json` themselves.
## API-key provider (`useApiKey` / `backendEnvironmentFile`)
```nix
services.hyperhive.agent.useApiKey = true; # default: false
services.hyperhive.agent.backendEnvironmentFile =
"/agents/myagent/harness/openrouter.env"; # default: null
services.hyperhive.agent.model = "anthropic/claude-3.5-sonnet"; # provider-specific model string
```
Runs this agent's `claude` against an API-key provider (for example OpenRouter)
instead of a Claude subscription via OAuth. Two options, paired — each
is a no-op without the other:
- **`useApiKey`** tells the harness itself not to wait for a Claude OAuth
session: at boot, `LoginState::from_dir` reports `Online` without
checking `~/.claude/` (`hive_agent::login::using_api_key`, reads
`HIVE_USE_API_KEY`), and the harness stamps the fact into the
consolidated harness state file so the operator dashboard also stops reading this
agent's empty `~/.claude/` as "needs login." An api-key agent that hits
a real 401 (the key itself is bad) still surfaces `needs_login` — the
harness skips only the boot-time "have I ever logged in" check, not
the auth-failure path.
- **`backendEnvironmentFile`** points at an operator-managed file
(outside the nix store, one `KEY=value` per line, systemd
`EnvironmentFile` syntax) supplying the credentials `claude` itself
reads from the environment — typically `ANTHROPIC_API_KEY` and
`ANTHROPIC_BASE_URL`. Loaded as an _optional_ `EnvironmentFile`
(leading `-`), so setting the option before the file exists doesn't
strand the harness at boot. With `useApiKey` set, the subagent daemon
(`hive-subagent-daemon`) loads the same file, so the agent's claude
subagents run on the same key.
Provision the file once, out of band (never through nix — an API key in
the store is world-readable and travels with the flake closure):
```sh
# on the host, once per agent that should use an api-key backend
sudo install -m 0600 -o root /dev/stdin \
/var/lib/hyperhive/agents/<name>/harness/openrouter.env <<KEYS
ANTHROPIC_BASE_URL=https://openrouter.ai/api/v1
ANTHROPIC_API_KEY=sk-or-...
KEYS
```
The file lives in the agent's bind-mounted **harness** dir, not `state/`
— `harness/` survives container rebuilds exactly like `state/` does, but
(unlike `state/`) is never bind-mounted into a parent agent's container
(see `docs/agent-lifecycle/persistence.md`'s "Parent access to child state"), so an API
key placed here is reachable by nothing but this agent and the host.
<!-- vale write-good.Passive = NO -->
⚠️ Verified end-to-end against OpenRouter hasn't happened as of this
writing — `ANTHROPIC_BASE_URL` support in the shipped Claude CLI is
documented behavior, not something this hive has run a live turn
against yet. Tool use, streaming, and MCP all need to keep working
through a non-Anthropic base URL; treat the first real agent on this
path as the actual verification, not this doc.
<!-- vale write-good.Passive = YES -->
Switching an already-provisioned OAuth agent to `useApiKey` leaves
`~/.claude/credentials.json` in place but unused — harmless, not
cleaned up automatically. Cost shape also changes: subscription pricing
→ per-request billing with no built-in monthly cap, worth knowing before
pointing a busy agent at a metered provider.