# Agent: Settings

**Page:** api/agent/settings

[Download Raw Markdown](./api/agent/settings.md)

---

{/* AUTO-GENERATED — Do not edit manually. Regenerate with: npm run docs:api:generate */}



The Agent Settings API exposes three groups of operations: the merged settings document (read and shallow-merge patch), the persisted model-fusion composites (list, upsert, delete), and the BYOA ACP backend (status report and per-agent secret storage). Settings and fusion are process-wide config with no realm dimension, so a per-request `X-Hoody-Realm` header is rejected with `realm_scope_unsupported`. Secret values are written to a 0600 store and never returned.

## Settings

### `GET /api/v1/agent/settings`

Returns the effective merged settings (home → project → `settings.local.json`, top-level merge) plus the home-layer object that `settings.patch` mutates. This is the new daemon RPC `settings.get`.

### Parameters

| Name | In | Type | Required | Description |
|------|----|------|----------|-------------|
| `X-Hoody-Cwd` | header | string | No | Per-request working-directory scope (§6.1): the .hoody project layer / record cwd / tool+workflow cwd. Required by routes that resolve a cwd. |
| `X-Hoody-Config-Dir` | header | string | No | Per-request `--config-dir` override (§6.1) selecting which on-disk .hoody install a stateless read/write resolves (HoodyPaths). |
| `X-Hoody-Container` | header | string | No | Per-request bound remote container (§6.1; omitted = local). Rejected (400) on routes with no container dimension. |
| `X-Hoody-Realm` | header | string | No | Per-request realm selector (§6.1): `"global"` or a 24-hex id (also accepted as `?realm=`). Rejected (400 `realm_scope_unsupported`) on active-only / no-realm routes. |
| `realm` | query | string | No | Per-request realm selector (§6.1) — the `in:query` alias of the `X-Hoody-Realm` header (read only when the header is absent): `"global"` or a 24-hex id. Rejected (400 `realm_scope_unsupported`) on active-only / no-realm routes. |

### Response



```json
{
  "merged": {
    "theme": "dark",
    "autoCompact": true,
    "model": "sonnet"
  },
  "home": {
    "theme": "dark",
    "autoCompact": true
  }
}
```


```json
{
  "code": "realm_scope_unsupported",
  "message": "realm scope not supported on this route"
}
```
| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `bad_request` | Bad request | The request was malformed or carried invalid parameters. | Correct the request body or query parameters. |
| `realm_scope_unsupported` | Realm scope unsupported | A per-request realm header was supplied to an active-only / global-no-realm RPC, which has no realm dimension to scope. | Omit the realm header on this route, or open a session to scope by realm. |


```json
{
  "code": "forbidden",
  "message": "request must arrive through the Hoody proxy"
}
```
| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `forbidden` | Forbidden (not via the Hoody proxy) | The request did not arrive through hoody-proxy: its source IP is private/local (in-container loopback, the bridge, the host, or a sibling container). The gateway has no service-level auth — authorization is owned by hoody-proxy, which is the only party that can reach it (TPROXY preserves the real public client IP). Kit network-position trust. | Reach the agent through hoody-proxy (e.g. `hoody agent …` → platform → proxy), not by connecting to the container directly. |


```json
{
  "code": "rate_limited",
  "message": "request rate limit exceeded"
}
```
| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `rate_limited` | Too many requests | The per-client request rate limit was exceeded; the gateway throttled the request before dispatch. | Honor the `Retry-After` header and retry; reduce the request rate. |


```json
{
  "code": "internal_error",
  "message": "internal server error"
}
```
| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `internal_error` | Internal error | An unexpected error occurred while handling the request. | Retry; if persistent, inspect the daemon logs. |



### SDK

```ts
const { data } = await client.agent.settings.getSettings();
```

---

### `PATCH /api/v1/agent/settings`

Applies a SHALLOW top-level merge into the home `~/.hoody/settings.json`. A `null` value deletes a key. Top-level only: sending `{"features":{...}}` REPLACES the whole `features` object. Returns the resulting home object.


Security-load-bearing keys (`deny_list`, `deny_urls`, `features`, `allowed_directories`, `hooks`, `disableAllHooks`, `mcp_servers`, `tools`) cannot be modified over HTTP and return `403 settings_key_protected`. Edit `settings.json` at the host to change a guardrail.


### Parameters

| Name | In | Type | Required | Description |
|------|----|------|----------|-------------|
| `X-Hoody-Cwd` | header | string | No | Per-request working-directory scope (§6.1): the .hoody project layer / record cwd / tool+workflow cwd. |
| `X-Hoody-Config-Dir` | header | string | No | Per-request `--config-dir` override (§6.1) selecting which on-disk .hoody install a stateless read/write resolves (HoodyPaths). |
| `X-Hoody-Container` | header | string | No | Per-request bound remote container (§6.1; omitted = local). Rejected (400) on routes with no container dimension. |
| `X-Hoody-Realm` | header | string | No | Per-request realm selector (§6.1): `"global"` or a 24-hex id. Rejected (400 `realm_scope_unsupported`) on active-only / no-realm routes. |
| `realm` | query | string | No | Per-request realm selector (§6.1) — the `in:query` alias of the `X-Hoody-Realm` header. |

### Request Body

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `patch` | object | Yes | Top-level keys to merge into the home `settings.json` (a `null` value deletes the key). |

```json
{
  "patch": {
    "theme": "dark",
    "autoCompact": true,
    "legacyKey": null
  }
}
```

### Response



```json
{
  "theme": "dark",
  "autoCompact": true,
  "model": "sonnet"
}
```


```json
{
  "code": "bad_request",
  "message": "invalid request"
}
```
| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `bad_request` | Bad request | The request was malformed or carried invalid parameters. | Correct the request body or query parameters. |
| `realm_scope_unsupported` | Realm scope unsupported | A per-request realm header was supplied to an active-only / global-no-realm RPC, which has no realm dimension to scope. | Omit the realm header on this route, or open a session to scope by realm. |


```json
{
  "code": "settings_key_protected",
  "message": "settings key 'deny_list' is security-load-bearing and cannot be modified over HTTP"
}
```
| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `settings_key_protected` | Settings key protected | The patch targets a security-load-bearing top-level settings key (`deny_list`, `features`, `allowed_directories`, `hooks`, `mcp_servers`, …). These guardrail keys cannot be modified over HTTP. | Edit `settings.json` at the host to change a guardrail key; omit it from the HTTP patch. |
| `forbidden` | Forbidden (not via the Hoody proxy) | The request did not arrive through hoody-proxy: its source IP is private/local. The gateway has no service-level auth — authorization is owned by hoody-proxy. Kit network-position trust. | Reach the agent through hoody-proxy (e.g. `hoody agent …` → platform → proxy), not by connecting to the container directly. |


```json
{
  "code": "payload_too_large",
  "message": "request body exceeds the configured size limit"
}
```
| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `payload_too_large` | Payload too large | The request body exceeds the configured size cap (`MaxBodyBytes`). The gateway rejects an oversized body at the edge (`http.MaxBytesReader`) before the handler reads it — a well-formed-but-large body is a size violation, not a JSON syntax error. | Reduce the request body below the configured limit (default 8 MiB); split a large payload into smaller requests. |


```json
{
  "code": "rate_limited",
  "message": "request rate limit exceeded"
}
```
| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `rate_limited` | Too many requests | The per-client request rate limit was exceeded; the gateway throttled the request before dispatch. | Honor the `Retry-After` header and retry; reduce the request rate. |


```json
{
  "code": "internal_error",
  "message": "internal server error"
}
```
| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `internal_error` | Internal error | An unexpected error occurred while handling the request. | Retry; if persistent, inspect the daemon logs. |



### SDK

```ts
const { data } = await client.agent.settings.patchSettings({
  body: { patch: { theme: "dark", autoCompact: true, legacyKey: null } }
});
```

---

## Fusion composites

### `GET /api/v1/agent/settings/fusion`

Lists the persisted model-fusion composites (`fusion.list`). Pass `?include_invalid=true` to also receive entries that failed validation (with a reason) so a broken composite is editable/deletable. This is a paginated list envelope.

### Parameters

| Name | In | Type | Required | Description |
|------|----|------|----------|-------------|
| `include_invalid` | query | boolean | No | When `true`, also return composites that failed validation (each with a reason) so a broken composite is editable/deletable. |
| `page` | query | integer | No | 1-based page number for pagination. |
| `limit` | query | integer | No | Maximum items per page (`0` = no pagination). |
| `X-Hoody-Cwd` | header | string | No | Per-request working-directory scope (§6.1). |
| `X-Hoody-Config-Dir` | header | string | No | Per-request `--config-dir` override (§6.1). |
| `X-Hoody-Container` | header | string | No | Per-request bound remote container (§6.1; omitted = local). |
| `X-Hoody-Realm` | header | string | No | Per-request realm selector (§6.1). Rejected (400 `realm_scope_unsupported`). |
| `realm` | query | string | No | Per-request realm selector (§6.1) — the `in:query` alias of the `X-Hoody-Realm` header. |

### Response



```json
{
  "items": [
    {
      "slug": "ensemble-fast",
      "name": "Ensemble Fast",
      "method": "majority",
      "members": ["haiku", "haiku-2"],
      "contextWindow": 8192
    }
  ],
  "meta": {
    "total": 1,
    "page": 1,
    "limit": 50
  }
}
```


```json
{
  "code": "bad_request",
  "message": "invalid request"
}
```
| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `bad_request` | Bad request | The request was malformed or carried invalid parameters. | Correct the request body or query parameters. |
| `realm_scope_unsupported` | Realm scope unsupported | A per-request realm header was supplied to an active-only / global-no-realm RPC, which has no realm dimension to scope. | Omit the realm header on this route, or open a session to scope by realm. |


```json
{
  "code": "forbidden",
  "message": "request must arrive through the Hoody proxy"
}
```
| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `forbidden` | Forbidden (not via the Hoody proxy) | The request did not arrive through hoody-proxy: its source IP is private/local. The gateway has no service-level auth — authorization is owned by hoody-proxy. Kit network-position trust. | Reach the agent through hoody-proxy (e.g. `hoody agent …` → platform → proxy), not by connecting to the container directly. |


```json
{
  "code": "not_found",
  "message": "resource not found"
}
```
| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `not_found` | Not found | The requested resource does not exist. | Verify the path and identifier. |


```json
{
  "code": "rate_limited",
  "message": "request rate limit exceeded"
}
```
| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `rate_limited` | Too many requests | The per-client request rate limit was exceeded; the gateway throttled the request before dispatch. | Honor the `Retry-After` header and retry; reduce the request rate. |


```json
{
  "code": "internal_error",
  "message": "internal server error"
}
```
| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `internal_error` | Internal error | An unexpected error occurred while handling the request. | Retry; if persistent, inspect the daemon logs. |


```json
{
  "code": "service_unavailable",
  "message": "service unavailable"
}
```
| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `service_unavailable` | Service unavailable | The daemon could not service the request (too busy, or a per-client stream concurrency cap was hit). | Honor `Retry-After` and retry. |



### SDK

```ts
for await (const composite of client.agent.settings.listFusionIterator({ include_invalid: true })) {
  console.log(composite.slug);
}
```

---

### `PUT /api/v1/agent/settings/fusion/{slug}`

Creates or updates a model-fusion composite keyed by `slug` (`fusion.upsert`). The body is the daemon `FusionSpec` under `spec`. Structural invariants (name/method/members, cycle guard, non-zero context window) are validated server-side.

### Parameters

| Name | In | Type | Required | Description |
|------|----|------|----------|-------------|
| `slug` | path | string | Yes | Path identifier. |
| `X-Hoody-Cwd` | header | string | No | Per-request working-directory scope (§6.1). |
| `X-Hoody-Config-Dir` | header | string | No | Per-request `--config-dir` override (§6.1). |
| `X-Hoody-Container` | header | string | No | Per-request bound remote container (§6.1; omitted = local). |
| `X-Hoody-Realm` | header | string | No | Per-request realm selector (§6.1). Rejected (400 `realm_scope_unsupported`). |
| `realm` | query | string | No | Per-request realm selector (§6.1) — the `in:query` alias of the `X-Hoody-Realm` header. |

### Request Body

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `spec` | object | Yes | The `FusionSpec` object (name, method, members, …). |

```json
{
  "spec": {
    "name": "Ensemble Fast",
    "method": "majority",
    "members": ["haiku", "haiku-2"],
    "contextWindow": 8192
  }
}
```

### Response



```json
{
  "slug": "ensemble-fast",
  "saved": true
}
```


```json
{
  "code": "bad_request",
  "message": "invalid request"
}
```
| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `bad_request` | Bad request | The request was malformed or carried invalid parameters. | Correct the request body or query parameters. |
| `realm_scope_unsupported` | Realm scope unsupported | A per-request realm header was supplied to an active-only / global-no-realm RPC, which has no realm dimension to scope. | Omit the realm header on this route, or open a session to scope by realm. |


```json
{
  "code": "forbidden",
  "message": "request must arrive through the Hoody proxy"
}
```
| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `forbidden` | Forbidden (not via the Hoody proxy) | The request did not arrive through hoody-proxy: its source IP is private/local. The gateway has no service-level auth — authorization is owned by hoody-proxy. Kit network-position trust. | Reach the agent through hoody-proxy (e.g. `hoody agent …` → platform → proxy), not by connecting to the container directly. |


```json
{
  "code": "not_found",
  "message": "resource not found"
}
```
| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `not_found` | Not found | The requested resource does not exist. | Verify the path and identifier. |


```json
{
  "code": "payload_too_large",
  "message": "request body exceeds the configured size limit"
}
```
| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `payload_too_large` | Payload too large | The request body exceeds the configured size cap (`MaxBodyBytes`). The gateway rejects an oversized body at the edge before the handler reads it. | Reduce the request body below the configured limit (default 8 MiB); split a large payload into smaller requests. |


```json
{
  "code": "rate_limited",
  "message": "request rate limit exceeded"
}
```
| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `rate_limited` | Too many requests | The per-client request rate limit was exceeded; the gateway throttled the request before dispatch. | Honor the `Retry-After` header and retry; reduce the request rate. |


```json
{
  "code": "internal_error",
  "message": "internal server error"
}
```
| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `internal_error` | Internal error | An unexpected error occurred while handling the request. | Retry; if persistent, inspect the daemon logs. |


```json
{
  "code": "service_unavailable",
  "message": "service unavailable"
}
```
| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `service_unavailable` | Service unavailable | The daemon could not service the request (too busy, or a per-client stream concurrency cap was hit). | Honor `Retry-After` and retry. |



### SDK

```ts
await client.agent.settings.upsertFusion({
  path: { slug: "ensemble-fast" },
  body: {
    spec: {
      name: "Ensemble Fast",
      method: "majority",
      members: ["haiku", "haiku-2"],
      contextWindow: 8192
    }
  }
});
```

---

### `DELETE /api/v1/agent/settings/fusion/{slug}`

Removes a model-fusion composite by `slug` (`fusion.delete`).

### Parameters

| Name | In | Type | Required | Description |
|------|----|------|----------|-------------|
| `slug` | path | string | Yes | Path identifier. |
| `X-Hoody-Cwd` | header | string | No | Per-request working-directory scope (§6.1). |
| `X-Hoody-Config-Dir` | header | string | No | Per-request `--config-dir` override (§6.1). |
| `X-Hoody-Container` | header | string | No | Per-request bound remote container (§6.1; omitted = local). |
| `X-Hoody-Realm` | header | string | No | Per-request realm selector (§6.1). Rejected (400 `realm_scope_unsupported`). |
| `realm` | query | string | No | Per-request realm selector (§6.1) — the `in:query` alias of the `X-Hoody-Realm` header. |

### Response



```json
{
  "removed": true
}
```


```json
{
  "code": "bad_request",
  "message": "invalid request"
}
```
| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `bad_request` | Bad request | The request was malformed or carried invalid parameters. | Correct the request body or query parameters. |
| `realm_scope_unsupported` | Realm scope unsupported | A per-request realm header was supplied to an active-only / global-no-realm RPC, which has no realm dimension to scope. | Omit the realm header on this route, or open a session to scope by realm. |


```json
{
  "code": "forbidden",
  "message": "request must arrive through the Hoody proxy"
}
```
| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `forbidden` | Forbidden (not via the Hoody proxy) | The request did not arrive through hoody-proxy: its source IP is private/local. The gateway has no service-level auth — authorization is owned by hoody-proxy. Kit network-position trust. | Reach the agent through hoody-proxy (e.g. `hoody agent …` → platform → proxy), not by connecting to the container directly. |


```json
{
  "code": "not_found",
  "message": "resource not found"
}
```
| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `not_found` | Not found | The requested resource does not exist. | Verify the path and identifier. |


```json
{
  "code": "rate_limited",
  "message": "request rate limit exceeded"
}
```
| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `rate_limited` | Too many requests | The per-client request rate limit was exceeded; the gateway throttled the request before dispatch. | Honor the `Retry-After` header and retry; reduce the request rate. |


```json
{
  "code": "internal_error",
  "message": "internal server error"
}
```
| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `internal_error` | Internal error | An unexpected error occurred while handling the request. | Retry; if persistent, inspect the daemon logs. |


```json
{
  "code": "service_unavailable",
  "message": "service unavailable"
}
```
| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `service_unavailable` | Service unavailable | The daemon could not service the request (too busy, or a per-client stream concurrency cap was hit). | Honor `Retry-After` and retry. |



### SDK

```ts
await client.agent.settings.deleteFusion({ path: { slug: "ensemble-fast" } });
```

---

## ACP backend

### `GET /api/v1/agent/acp/agents`

Reports the BYOA delegated-session backend availability (`codex` / `claude` / `gemini` / `opencode`) — enabled flag, on-PATH status, trust posture (`acp.status`). A fixed status object, NOT a paginated collection.


A `X-Hoody-Realm` header WITHOUT a `X-Hoody-Container` returns `400 realm_scope_unsupported` (the local report has no realm dimension). For REMOTE BYOA, a bound `X-Hoody-Container` switches the report to ON-CONTAINER detection/login probing, and `X-Hoody-Realm` scopes that probe.


### Parameters

| Name | In | Type | Required | Description |
|------|----|------|----------|-------------|
| `X-Hoody-Cwd` | header | string | No | Per-request working-directory scope (§6.1). |
| `X-Hoody-Config-Dir` | header | string | No | Per-request `--config-dir` override (§6.1). |
| `X-Hoody-Container` | header | string | No | Per-request bound remote container (§6.1; omitted = local). |
| `X-Hoody-Realm` | header | string | No | Per-request realm selector (§6.1): `"global"` or a 24-hex id. Rejected (400 `realm_scope_unsupported`) on active-only / no-realm routes. |
| `realm` | query | string | No | Per-request realm selector (§6.1) — the `in:query` alias of the `X-Hoody-Realm` header. |

### Response



```json
{
  "codex":    { "enabled": true,  "onPath": true,  "trusted": true  },
  "claude":   { "enabled": true,  "onPath": true,  "trusted": true  },
  "gemini":   { "enabled": false, "onPath": false, "trusted": false },
  "opencode": { "enabled": true,  "onPath": false, "trusted": false }
}
```


```json
{
  "code": "realm_scope_unsupported",
  "message": "realm scope not supported on this route"
}
```
| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `bad_request` | Bad request | The request was malformed or carried invalid parameters. | Correct the request body or query parameters. |
| `realm_scope_unsupported` | Realm scope unsupported | A per-request realm header was supplied to an active-only / global-no-realm RPC, which has no realm dimension to scope. | Omit the realm header on this route, or open a session to scope by realm. |


```json
{
  "code": "forbidden",
  "message": "request must arrive through the Hoody proxy"
}
```
| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `forbidden` | Forbidden (not via the Hoody proxy) | The request did not arrive through hoody-proxy: its source IP is private/local. The gateway has no service-level auth — authorization is owned by hoody-proxy. Kit network-position trust. | Reach the agent through hoody-proxy (e.g. `hoody agent …` → platform → proxy), not by connecting to the container directly. |


```json
{
  "code": "not_found",
  "message": "resource not found"
}
```
| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `not_found` | Not found | The requested resource does not exist. | Verify the path and identifier. |


```json
{
  "code": "rate_limited",
  "message": "request rate limit exceeded"
}
```
| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `rate_limited` | Too many requests | The per-client request rate limit was exceeded; the gateway throttled the request before dispatch. | Honor the `Retry-After` header and retry; reduce the request rate. |


```json
{
  "code": "internal_error",
  "message": "internal server error"
}
```
| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `internal_error` | Internal error | An unexpected error occurred while handling the request. | Retry; if persistent, inspect the daemon logs. |


```json
{
  "code": "service_unavailable",
  "message": "service unavailable"
}
```
| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `service_unavailable` | Service unavailable | The daemon could not service the request (too busy, or a per-client stream concurrency cap was hit). | Honor `Retry-After` and retry. |



### SDK

```ts
const { data } = await client.agent.settings.getACPStatus();
```

---

### `PUT /api/v1/agent/acp/agents/{agent}/secrets/{key}`

Stores (or clears) one per-backend env VALUE for a BYOA ACP agent (`acp.set_secret`) in the dedicated 0600 `~/.hoody/acp-secrets.env` store under `acp/<agent>/` (atomic temp+rename, flock). `settings.json` holds only the env KEY NAMES; the VALUE lives ONLY in the 0600 store. An empty value DELETES (unsets) the reference.


The value is NEVER returned — the reply confirms only `(agent, key, stored|cleared)`. The HTTP edge has no service-level auth (hoody-proxy is the boundary, kit network-position trust).


### Parameters

| Name | In | Type | Required | Description |
|------|----|------|----------|-------------|
| `agent` | path | string | Yes | Path identifier. |
| `key` | path | string | Yes | Path identifier. |
| `X-Hoody-Cwd` | header | string | No | Per-request working-directory scope (§6.1). |
| `X-Hoody-Config-Dir` | header | string | No | Per-request `--config-dir` override (§6.1). |
| `X-Hoody-Container` | header | string | No | Per-request bound remote container (§6.1; omitted = local). |
| `X-Hoody-Realm` | header | string | No | Per-request realm selector (§6.1). Rejected (400 `realm_scope_unsupported`). |
| `realm` | query | string | No | Per-request realm selector (§6.1) — the `in:query` alias of the `X-Hoody-Realm` header. |

### Request Body

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `value` | string | No | The env secret value. Empty string clears (unsets) the reference. Stored only in the 0600 `acp-secrets.env` store. |

```json
{
  "value": "sk-live-EXAMPLE-1234567890abcdef"
}
```

### Response



```json
{
  "agent": "codex",
  "key": "OPENAI_API_KEY",
  "stored": true,
  "cleared": false
}
```


```json
{
  "code": "bad_request",
  "message": "invalid request"
}
```
| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `bad_request` | Bad request | The request was malformed or carried invalid parameters. | Correct the request body or query parameters. |
| `realm_scope_unsupported` | Realm scope unsupported | A per-request realm header was supplied to an active-only / global-no-realm RPC, which has no realm dimension to scope. | Omit the realm header on this route, or open a session to scope by realm. |


```json
{
  "code": "admin_unauthorized",
  "message": "memory administration requires a valid admin token"
}
```
| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `admin_unauthorized` | Rejected by the daemon's own admin gate | The daemon's Unix-socket `memAdminGate` / `systemAdminGate` refused the request. The HTTP edge has no service-level auth (hoody-proxy is the boundary, kit network-position trust), but the daemon retains its OWN socket-side admin gate: when an admin capability is configured on the daemon WITHOUT a matching forwarded `admin_token`, the daemon refuses. In the standard HTTP deployment the daemon runs with socket auth and no admin capability, so this gate allows the request and this code is not emitted. | Run the daemon with socket auth (`--auth-token-path`) and no separate admin capability so its own gate allows HTTP requests forwarded from the gateway; or, for the interactive TUI Memory tab over the socket, present the daemon's configured Memory-admin token. |
| `forbidden` | Forbidden (not via the Hoody proxy) | The request did not arrive through hoody-proxy: its source IP is private/local. The gateway has no service-level auth — authorization is owned by hoody-proxy. Kit network-position trust. | Reach the agent through hoody-proxy (e.g. `hoody agent …` → platform → proxy), not by connecting to the container directly. |


```json
{
  "code": "unknown_agent",
  "message": "unknown ACP agent: evilbot (known: codex, claude, gemini, opencode)"
}
```
| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `not_found` | Not found | The requested resource does not exist. | Verify the path and identifier. |
| `unknown_agent` | Unknown ACP agent | The named ACP agent is not a known BYOA backend, so a per-agent secret reference would be dead (no launch spec reads it). | Use a known agent: `codex`, `claude`, `gemini`, or `opencode`. |


```json
{
  "code": "payload_too_large",
  "message": "request body exceeds the configured size limit"
}
```
| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `payload_too_large` | Payload too large | The request body exceeds the configured size cap (`MaxBodyBytes`). The gateway rejects an oversized body at the edge before the handler reads it. | Reduce the request body below the configured limit (default 8 MiB); split a large payload into smaller requests. |


```json
{
  "code": "rate_limited",
  "message": "request rate limit exceeded"
}
```
| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `rate_limited` | Too many requests | The per-client request rate limit was exceeded; the gateway throttled the request before dispatch. | Honor the `Retry-After` header and retry; reduce the request rate. |


```json
{
  "code": "internal_error",
  "message": "internal server error"
}
```
| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `internal_error` | Internal error | An unexpected error occurred while handling the request. | Retry; if persistent, inspect the daemon logs. |


```json
{
  "code": "service_unavailable",
  "message": "service unavailable"
}
```
| Error Code | Title | Description | Resolution |
|------------|-------|-------------|------------|
| `service_unavailable` | Service unavailable | The daemon could not service the request (too busy, or a per-client stream concurrency cap was hit). | Honor `Retry-After` and retry. |



### SDK

```ts
await client.agent.settings.setACPSecret({
  path: { agent: "codex", key: "OPENAI_API_KEY" },
  body: { value: "sk-live-EXAMPLE-1234567890abcdef" }
});
```