Add daemon.max_handles config to cap concurrent agents per daemon #1

Open
opened 2026-05-06 05:44:55 +00:00 by anuna-02 · 0 comments
anuna-02 commented 2026-05-06 05:44:55 +00:00 (Migrated from codeberg.org)

Context

hark's daemon currently allows an unbounded number of concurrent agent handles. Each init call creates a new handle, a new WebSocket to the router, and a new per-handle queue with up to max_messages_per_handle messages and max_bytes_per_handle bytes.

A buggy or malicious local process can exhaust daemon resources by repeatedly calling init:

  • Aggregate memory bounded only by max_bytes_per_handle × handle_count, with handle_count uncapped.
  • Each handle creates a tokio task plus its own outbound WebSocket task.
  • File descriptors and ephemeral ports scale with handle count.

For a single-operator workstation this is acceptable. For shared hosts, CI runners, or any context where local processes are not fully trusted, an explicit cap is required.

Proposed change

Add a daemon.max_handles field to config.toml with a sensible default (suggest 64).

Reject init with a stable error code (daemon_at_capacity) when the cap is reached. Surface the limit and current count in daemon status output.

Acceptance

  • daemon.max_handles parsed from config; default 64; documented in README and specs/config.md.
  • init returns daemon_at_capacity when at limit (suggest HTTP 503 + structured error, plus a new exit code).
  • daemon status shows handles: N / M.
  • Integration test: fill daemon to capacity, assert next init is rejected; close frees a slot, subsequent init succeeds.

Refs

  • cbcl-runtime deck slide 17 (Flow control)
  • Surfaces the gap noted in PROTO-002 NDI review
## Context `hark`'s daemon currently allows an unbounded number of concurrent agent handles. Each `init` call creates a new handle, a new WebSocket to the router, and a new per-handle queue with up to `max_messages_per_handle` messages and `max_bytes_per_handle` bytes. A buggy or malicious local process can exhaust daemon resources by repeatedly calling `init`: - Aggregate memory bounded only by `max_bytes_per_handle × handle_count`, with `handle_count` uncapped. - Each handle creates a tokio task plus its own outbound WebSocket task. - File descriptors and ephemeral ports scale with handle count. For a single-operator workstation this is acceptable. For shared hosts, CI runners, or any context where local processes are not fully trusted, an explicit cap is required. ## Proposed change Add a `daemon.max_handles` field to `config.toml` with a sensible default (suggest 64). Reject `init` with a stable error code (`daemon_at_capacity`) when the cap is reached. Surface the limit and current count in `daemon status` output. ## Acceptance - [ ] `daemon.max_handles` parsed from config; default 64; documented in README and `specs/config.md`. - [ ] `init` returns `daemon_at_capacity` when at limit (suggest HTTP 503 + structured error, plus a new exit code). - [ ] `daemon status` shows `handles: N / M`. - [ ] Integration test: fill daemon to capacity, assert next `init` is rejected; `close` frees a slot, subsequent `init` succeeds. ## Refs - `cbcl-runtime` deck slide 17 (Flow control) - Surfaces the gap noted in PROTO-002 NDI review
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
anuna-research/hark#1
No description provided.