Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 34 additions & 2 deletions reference/configuration/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,7 @@ rootPath: /var/lib/harper

Added in: v5.2.0

Built-in Harper agent β€” an LLM loop that operates this instance through Harper's own operations, scoped filesystem access, followup scheduling, the V8 inspector, and outbound HTTP. Disabled by default, so it never incurs LLM cost unless you turn it on. Driven through the [Agent operations](../operations-api/operations.md#agent), which also describe the privilege boundary before you enable it.
Built-in Harper agent β€” an LLM loop that operates this instance through Harper's own operations, scoped filesystem access, followup scheduling, the V8 inspector, and outbound HTTP. Disabled by default, so it never incurs LLM cost unless you turn it on. Driven through the [Agent operations](../operations-api/operations.md#agent), which also describe the privilege boundary before you enable it. Each of its own tool groups can be [turned off](#turning-off-tool-groups).

```yaml
agent:
Expand Down Expand Up @@ -488,9 +488,41 @@ agent:
- `componentsScope` β€” The agent's `components` filesystem scope, which it reads and, with `allowDestructive`, writes; absolute or relative to `rootPath`. Read at startup only; _Default_: the full `componentsRoot`
- `configScope` <VersionBadge version="v5.4.0" /> β€” The agent's read-only `config` filesystem scope: a file or a directory, absolute or relative to `rootPath`. Read at startup only. See [Filesystem scopes](#filesystem-scopes); _Default_: the Harper config file only
- `httpFetch` <VersionBadge version="v5.4.0" /> β€” Whether the agent has its `http_fetch` tool, and which hosts it may reach: `true`, `false`, or `{ allow: [...] }`. Read at startup only. See [Restricting `http_fetch`](#restricting-http_fetch); _Default_: `true`
- `tools` <VersionBadge version="v5.4.0" /> β€” Which of the agent's own tool groups are in its toolset, one boolean each: `filesystem`, `schedule`, `inspector`, and `bestPractices`. `false` removes the group. Read at startup only. See [Turning off tool groups](#turning-off-tool-groups); _Default_: every group on
- `systemPromptAppend` β€” Operator text appended to the agent's system prompt

`enabled`, `provider`, `model`, `maxTurns`, `maxTokens`, `maxToolResultBytes`, `maxSessionTokens`, `maxCostUsd`, `autoApprove`, `allowDestructive`, and `systemPromptAppend` can also be changed at runtime with [`set_agent_config`](../operations-api/operations.md#set_agent_config), which applies in memory only. `enabled` is the exception worth knowing: it cannot switch the agent on, because with the agent disabled at startup no agent operation is registered at all. `httpFetch`, `componentsScope`, and `configScope` are read at startup only, and `set_agent_config` rejects them.
`enabled`, `provider`, `model`, `maxTurns`, `maxTokens`, `maxToolResultBytes`, `maxSessionTokens`, `maxCostUsd`, `autoApprove`, `allowDestructive`, and `systemPromptAppend` can also be changed at runtime with [`set_agent_config`](../operations-api/operations.md#set_agent_config), which applies in memory only. `enabled` is the exception worth knowing: it cannot switch the agent on, because with the agent disabled at startup no agent operation is registered at all. `httpFetch`, `tools`, `componentsScope`, and `configScope` are read at startup only, and `set_agent_config` rejects them. [`get_agent_config`](../operations-api/operations.md#get_agent_config) returns the configuration in effect, the startup-only keys included.

### Turning off tool groups

<VersionBadge version="v5.4.0" />

Besides the operations tools, which run as `agent.user`, the agent has tools of its own that run at the Harper process's privilege: the filesystem tools, `schedule_followup`, the V8 inspector tools, `http_fetch`, and the best-practices lookup. `allowDestructive: false` removes only the ones marked destructive, and `maxTurns: 1` still lets the model call tools within that turn. To run the agent without a group, turn it off under `tools`:

```yaml
agent:
enabled: true
httpFetch: false
tools:
filesystem: false
schedule: false
inspector: false
bestPractices: false
```

| Key | Tools removed when `false` |
| --------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `filesystem` | `read_file`, `write_file`, `list_dir`, `grep_files`, `tail_file` |
| `schedule` | `schedule_followup` |
| `inspector` | `inspector_attach`, `inspector_evaluate`, `inspector_set_breakpoint`, `inspector_set_logpoint`, `inspector_profile_cpu` |
| `bestPractices` | `harper_best_practice`, and the best-practices overview leaves the system prompt |

Every key defaults to `true`, so an existing configuration is unchanged. The behavior worth knowing:

- **A group that is off is gone, not gated.** The model is sent no schema for its tools, the system prompt does not describe them, and a call to one by name is answered as an unknown tool and runs nothing. With every group and `httpFetch` off, the toolset holds only the operations tools `agent.user` may call, which is the shape for an application that sends the agent a prepared brief and wants an answer in one turn.
- **A disabled group's tool names stay reserved.** No operations tool or injected tool can take the name of a tool that is off, so turning a group off never changes what a call to one of its names does. This was already so for `http_fetch`.
- **Read at startup only.** Set it in the configuration file, through `set_configuration`, through `HARPER_SET_CONFIG`, or with the `AGENT_TOOLS_FILESYSTEM`, `AGENT_TOOLS_SCHEDULE`, `AGENT_TOOLS_INSPECTOR` and `AGENT_TOOLS_BESTPRACTICES` environment variables or CLI flags, then restart. `set_agent_config` rejects a request that includes `tools` with a 400 and applies nothing from it; a later `set_agent_config` that changes `allowDestructive` rebuilds the toolset with the same switches. `get_agent_config` reports the switches in effect, so an application can check at startup that the groups it needs off are off. As with `httpFetch`, a switch holds against the agent itself only while `set_configuration` and `restart` stay out of its toolset (they are not in the default operations allow list) or behind [approval](../operations-api/operations.md#approve_agent_action): with both, a prompt-steered run could write the switch back on and restart.
- **A malformed value turns groups off, never on.** A value other than `true` or `false` turns its group off, and an unknown key under `tools`, or a `tools` that is not a map, turns every group off, since a misspelled key may have been meant to turn a group off. The agent logs an error naming what to correct and starts with the rest of its configuration.

### Filesystem scopes

Expand Down
35 changes: 31 additions & 4 deletions reference/operations-api/operations.md
Original file line number Diff line number Diff line change
Expand Up @@ -2039,13 +2039,13 @@ Operations for driving Harper's built-in agent β€” an LLM loop that operates the

The agent component is **disabled by default**. Enable it with `agent.enabled: true` in `harper-config.yaml` (see [`agent`](../configuration/options.md#agent)) and configure a generative model under [`models`](../models/overview.md#configuration). With the component disabled at startup none of these operations are registered, so calling one is an unknown-operation error rather than a permission or state error.

All six operations are `super_user` by default. They participate in the role [`operations` allowlist](../users-and-roles/overview.md#operation-permissions), so a non-`super_user` role can be granted a scoped subset without granting full `super_user` β€” either individual names (`operations: ['agent_prompt', 'get_agent_session']`) or the built-in [`agent` permission group](../users-and-roles/overview.md#operation-permissions), which covers all of these except `set_agent_config`. Note that the read operations are not caller-scoped: a role granted `get_agent_session` or `list_agent_sessions` reads every session on the instance, including transcripts of runs it did not start. Because a transcript records the _arguments and output_ of every tool call, and those calls ran as `agent.user`, delegating a read operation hands that role the results of work done at the agent's privilege β€” table contents, log excerpts, configuration β€” regardless of its own permissions. Delegate the read operations only to roles you would trust with the agent itself.
All seven operations are `super_user` by default. They participate in the role [`operations` allowlist](../users-and-roles/overview.md#operation-permissions), so a non-`super_user` role can be granted a scoped subset without granting full `super_user` β€” either individual names (`operations: ['agent_prompt', 'get_agent_session']`) or the built-in [`agent` permission group](../users-and-roles/overview.md#operation-permissions), which covers all of these except `set_agent_config` and `get_agent_config`. Note that the read operations are not caller-scoped: a role granted `get_agent_session` or `list_agent_sessions` reads every session on the instance, including transcripts of runs it did not start. Because a transcript records the _arguments and output_ of every tool call, and those calls ran as `agent.user`, delegating a read operation hands that role the results of work done at the agent's privilege β€” table contents, log excerpts, configuration β€” regardless of its own permissions. Delegate the read operations only to roles you would trust with the agent itself.

:::warning
Anyone who can call `agent_prompt` can direct whatever the agent does. Understand the boundary before enabling it:

- `agent.user` (default: a `super_user` bootstrap identity) governs only the **operations** tools. Setting it to a restricted user narrows those, and nothing else.
- The agent's other tools β€” scoped filesystem access, outbound `http_fetch`, followup scheduling, and the V8 inspector β€” run at the Harper process's own privilege, whatever `agent.user` is. (The inspector tools additionally need `threads.debug`, and fail with an explanatory error without it.)
- The agent's other tools β€” scoped filesystem access, outbound `http_fetch`, followup scheduling, the V8 inspector, and the best-practices lookup β€” run at the Harper process's own privilege, whatever `agent.user` is. (The inspector tools additionally need `threads.debug`, and fail with an explanatory error without it.) Since v5.4.0, each of these groups can be removed from the toolset at startup with [`agent.tools`](../configuration/options.md#turning-off-tool-groups) and [`agent.httpFetch`](../configuration/options.md#restricting-http_fetch); with all of them off, the agent has only the operations tools `agent.user` may call.
- By default, `http_fetch` blocks only cloud-metadata hosts and the IPv4 link-local range `169.254.0.0/16`. It checks host names, not resolved addresses, so a name that resolves to a blocked address is not caught. Since v5.4.0, it also checks every redirect hop before following it. Every other host is reachable, including anything private or internal the server can route to. Reading is ungated too. By default, `read_file` covers the component tree, the log directory, and the Harper config file. Before v5.4.0, it covered the whole directory holding the config file. `componentsScope` and `configScope` can point it elsewhere, including somewhere wider. Every scope refuses Harper's key directories, key file names, and PEM private keys. See [Filesystem scopes](../configuration/options.md#filesystem-scopes). An enabled agent therefore has a read path and an egress path in the same toolset. Unless the agent needs the network, set [`agent.httpFetch`](../configuration/options.md#restricting-http_fetch) to `false` to remove the tool, or to an allow-list of the hosts it needs. Otherwise, treat it as an outbound network client and apply egress policy to the host.
- With the default `agent.allowDestructive: false`, destructive tools (including filesystem writes) are removed from the toolset entirely. Turning it on admits component writes, and component code is executed by the Harper process β€” a write is effectively code execution at process privilege.
- Leave `agent.autoApprove` off so any destructive call that is admitted still pauses for [approval](#approve_agent_action). The gate covers only the tools marked destructive β€” filesystem writes, the inspector's code-evaluation tools, and the operations on MCP's [curated destructive set](../mcp/tool-metadata.md) (`drop_table`, `delete`, `restart`, `set_configuration`, ...). `http_fetch` and followup scheduling are not gated, so an outbound POST and a self-rescheduling run proceed without an approval prompt.
Expand All @@ -2060,6 +2060,7 @@ Anyone who can call `agent_prompt` can direct whatever the agent does. Understan
| `approve_agent_action` | Approves or denies a gated tool call and resumes the run | super_user |
| `cancel_agent_run` | Cancels a run and marks the session aborted | super_user |
| `set_agent_config` | Updates agent settings in memory for the life of the process | super_user |
| `get_agent_config` | Returns the agent settings in effect | super_user |

### Sessions and run status

Expand Down Expand Up @@ -2220,7 +2221,7 @@ One gap is worth knowing: changing `allowDestructive` with [`set_agent_config`](

<VersionBadge type="changed" version="v5.4.0" />

Updates agent settings and returns the resulting configuration. Accepts any of `enabled`, `provider`, `model`, `maxTurns`, `maxTokens`, `maxToolResultBytes`, `maxSessionTokens`, `maxCostUsd`, `autoApprove`, `allowDestructive`, and `systemPromptAppend`; keys not supplied are left unchanged. Set `maxSessionTokens` or `maxCostUsd` to `null` to remove that cap. Each field is described under [`agent`](../configuration/options.md#agent). A request that includes `httpFetch`, `componentsScope`, or `configScope` is rejected with a 400 and nothing in it is applied: the [`http_fetch` policy](../configuration/options.md#restricting-http_fetch) and the [filesystem scopes](../configuration/options.md#filesystem-scopes) are read at startup only. A `maxTurns` or `maxTokens` that is not a positive integer, or a cap that is not a usable number, is rejected the same way. A `maxToolResultBytes` that is not an integer from `1024` to `1048576` is rejected the same way.
Updates agent settings and returns the resulting configuration. Accepts any of `enabled`, `provider`, `model`, `maxTurns`, `maxTokens`, `maxToolResultBytes`, `maxSessionTokens`, `maxCostUsd`, `autoApprove`, `allowDestructive`, and `systemPromptAppend`; keys not supplied are left unchanged. Set `maxSessionTokens` or `maxCostUsd` to `null` to remove that cap. Each field is described under [`agent`](../configuration/options.md#agent). A request that includes `httpFetch`, `tools`, `componentsScope`, or `configScope` is rejected with a 400 and nothing in it is applied: the [`http_fetch` policy](../configuration/options.md#restricting-http_fetch), the [tool groups](../configuration/options.md#turning-off-tool-groups) and the [filesystem scopes](../configuration/options.md#filesystem-scopes) are read at startup only. A `maxTurns` or `maxTokens` that is not a positive integer, or a cap that is not a usable number, is rejected the same way. A `maxToolResultBytes` that is not an integer from `1024` to `1048576` is rejected the same way.

```json
{ "operation": "set_agent_config", "autoApprove": false, "maxTurns": 20 }
Expand All @@ -2232,9 +2233,35 @@ Three limits are worth knowing:
- **A run already in flight keeps the settings it started with** β€” its toolset, `autoApprove`, `model`, `maxTurns`, `maxTokens`, `maxToolResultBytes`, `systemPromptAppend` and spend caps are all captured at start. Changes take effect on the next run, and a paused run that `approve_agent_action` resumes counts as a new one: it picks up the current settings. To stop a run immediately, use `cancel_agent_run`.
- **`enabled` is not a kill switch.** It cannot turn the agent on β€” if it was off at startup, this operation does not exist. Setting it to `false` only makes subsequent `agent_prompt` calls return 409; a run already in flight continues, and `approve_agent_action` still resumes a paused one. Use `cancel_agent_run` to stop a run.

### `get_agent_config`

<VersionBadge version="v5.4.0" />

Returns the agent configuration in effect: the startup-only keys as resolved at startup (`httpFetch`, `tools`, `componentsScope`, `configScope`, `user`), and the runtime-tunable keys as last set by `set_agent_config`. It takes no parameters and changes nothing. An application that embeds the agent can call it at startup to confirm that the [tool groups](../configuration/options.md#turning-off-tool-groups) it needs off are off. Like `set_agent_config`, it is outside the `agent` permission group and is not exposed over MCP; grant it to a role by name if a delegated role needs it.

```json
{ "operation": "get_agent_config" }
```

```json
{
"enabled": true,
"maxTurns": 50,
"maxTokens": 16384,
"maxToolResultBytes": 65536,
"autoApprove": false,
"allowDestructive": false,
"user": "hdb_agent",
"httpFetch": false,
"tools": { "filesystem": false, "schedule": false, "inspector": false, "bestPractices": false }
}
```

A `tools` value reflects what the agent resolved, so a malformed setting shows as the groups it turned off. `provider`, `model`, `componentsScope`, `configScope`, `maxSessionTokens`, `maxCostUsd` and `systemPromptAppend` appear only when they are set.

### MCP access

When the [MCP server](../mcp/overview.md) is enabled with the operations profile, `agent_prompt`, `get_agent_session`, `list_agent_sessions`, `approve_agent_action`, and `cancel_agent_run` are also exposed as MCP tools, with no allow-list entry required. They dispatch through the same authorization path as the operations above, and are listed only for users whose role could call them. `set_agent_config` is deliberately not exposed over MCP β€” it is an operator action.
When the [MCP server](../mcp/overview.md) is enabled with the operations profile, `agent_prompt`, `get_agent_session`, `list_agent_sessions`, `approve_agent_action`, and `cancel_agent_run` are also exposed as MCP tools, with no allow-list entry required. They dispatch through the same authorization path as the operations above, and are listed only for users whose role could call them. `set_agent_config` and `get_agent_config` are deliberately not exposed over MCP β€” they are operator actions.

---

Expand Down
Loading
Loading