Watch
0
0
Fork
You've already forked hyperhive
0

templates: the agent system prompt is a Jinja template, rendered through hive-template

system.md carries {{ label }}-style variables and an {% if not archetype %} block in place of the config:repo / config:archetype marker pairs, so prompt.rs drops its line filter, marker parsers and string replaces. The rendered prompt is byte for byte the old one for a custom agent, an archetype agent and an empty archetype name, with and without hive, swarm, docs and operators. hive-template now drops a block tag's own line.
This commit is contained in:
damocles 2026-11-11 02:26:25 +01:00 • committed by mara
commit c0eb6780ec
3 changed files with 165 additions and 242 deletions

View file

@ -105,16 +105,9 @@ state dirs work as for every other agent.
`/agents/<name>/state` (so it can manage any agent's state dir; config
isn't mounted, since a real config change is a PR from a clone), plus an RO mount for
`/meta` (the hive's topology and limits files). Any agent holding it gets the same mounts.
- **Prompt** — identical for every container but one block (below):
`prompts/system.md`
carries `<!-- role:agent -->` / `<!-- role:manager -->` marker
blocks, and `prompt::render` filters for `"agent"` unconditionally,
manager included ("always `agent` role — there is only one role",
`hive-agent/src/prompt.rs`'s own module doc). The `role:manager`
blocks are dead in production, exercised only by a unit test
(`filter_blocks(SAMPLE, "role", "manager")`). The one block that differs
is `<!-- config:repo -->` vs `<!-- config:archetype -->`: an agent built
from an [archetype](../swarm/archetypes.md) is told it has no config repo.
- **Prompt** — identical for every container but one paragraph: an agent
built from an [archetype](../swarm/archetypes.md) is told it has no config
repo, every other agent is told how to propose changes to its own.
- **Tool allow-list** — the MCP tools claude sees come from the agent's
permissions alone, the same mechanism for every agent
([`docs/4-implementation/turn-loop/mcp.md`](../../4-implementation/turn-loop/mcp.md)). Ruth's permissions

View file

@ -297,8 +297,7 @@ definition, then create ruth from the swarm dashboard.
The system prompt (`hive-agent/prompts/system.md`, rendered by
`hive-agent/src/prompt.rs`) is the **same for every agent**; what
varies is which MCP tools it surfaces (gated by the agent's permissions,
which the swarm sets). No `role:manager` block renders only
for the root agent. The root agent's role-specific
which the swarm sets). The root agent's role-specific
behaviour comes from its AGENTS.md / agent-specific instructions, not
the system prompt template.

View file

@ -253,26 +253,25 @@ needs to `chown` a bind mount), once at startup:
race), trading that for a hard dependency on the daemon's uptime
(`Restart=always`, no stdio fallback). Extra servers stay stdio.
- `claude-system-prompt.md` — rendered from
`hive-agent/prompts/system.md` by `hive-agent`'s `prompt::render`:
HTML-comment markers (`<!-- role:agent -->...<!-- /role:agent -->`,
same for `role:manager`) gate the role-specific blocks; both flavors
share everything else. `<!-- config:repo -->` and
`<!-- config:archetype -->` blocks gate the config-repo paragraphs: an
`hive-agent/prompts/system.md` by `hive-agent`'s `prompt::render`: a
[Jinja template](../../../hive-template/README.md) (`{{ name }}` for a
value, `{% if %}` for a block). An
`{% if not archetype %}` / `{% else %}` pair gates the config-repo paragraphs: an
agent with `HIVE_ARCHETYPE` set (the meta flake sets it on an agent built
from an [archetype](../../2-handbook/swarm/archetypes.md)) gets the archetype block and
every other agent the repo block, with `{archetype}` filled in with the
archetype's name. Five placeholders are then
substituted: `{label}` (short agent name), `{qualified_label}`
from an [archetype](../../2-handbook/swarm/archetypes.md)) gets the archetype
block, with `{{ archetype }}` filled in with the archetype's name, and every
other agent the repo block. Five variables are
set: `{{ label }}` (short agent name), `{{ qualified_label }}`
(hive-qualified `name@domain` form),
`{hive_identity}` (for example `` on hive `pr1ma` ``; empty when
`HYPERHIVE_HIVE_NAME` is unset), `{swarm_identity}` (same
shape for the swarm), and `{operators}`: a paragraph listing the
`{{ hive_identity }}` (for example `` on hive `pr1ma` ``; empty when
`HYPERHIVE_HIVE_NAME` is unset), `{{ swarm_identity }}` (same
shape for the swarm), and `{{ operators }}`: a paragraph listing the
swarm's operators with the pronouns from each one's forge profile,
for example `Operators: mara (she/her), sol.`. The harness reads
them with one direct get on the one key of the `operator-profiles`
KV bucket, which `swarm-controller` writes. The harness waits up to five seconds for
them. When the bucket is empty or doesn't answer in time,
`{operators}` is empty and the prompt names no operator. Either way
`{{ operators }}` is empty and the prompt names no operator. Either way
the template tells agents to say "the operator" in third person. A
pronoun change reaches an agent at its next harness start, since
the prompt renders once per start.
@ -281,17 +280,11 @@ needs to `chown` a bind mount), once at startup:
telling the agent where the docs live.
Passed via `--system-prompt-file`.
**Marker grammar.** `<!-- KIND:X -->` opens a block; any
`<!-- /KIND:X -->` closes the current block of that kind. The renderer
filters the two kinds one after the other. The renderer always uses
role `agent`, so it elides blocks with other role tags, and config `repo`
or `archetype` as above. Nesting **isn't**
supported — a stray opener with no closer runs until end of file.
The renderer tolerates whitespace inside markers (`<!--role:foo-->` parses the
same as `<!-- role:foo -->`). Content outside any marker is always
included. Today's `system.md` carries no role markers (single agent
role), and the role grammar stays wired for a future manager / multi-role
prompt; it carries one pair of config blocks.
**Template rules.** A variable the template names but the renderer doesn't
set is an error. The harness then writes the template unrendered and logs the
reason, so a typo shows up in the prompt instead of as an empty string. A
block tag on a line of its own leaves no blank line behind. A lone `{` or `}`
is plain text.
**`hive_identity` / `swarm_identity` shape.** Each carries a
leading space + backticked name (` on hive \`pr1ma\``,