Skip to content

feat(wrap): make PTY ring-buffer configurable via env vars#1166

Merged
geoffjay merged 2 commits intomainfrom
issue-1164
Apr 18, 2026
Merged

feat(wrap): make PTY ring-buffer configurable via env vars#1166
geoffjay merged 2 commits intomainfrom
issue-1164

Conversation

@geoffjay
Copy link
Copy Markdown
Owner

Add AGENTD_WRAP_HISTORY_BYTES and AGENTD_WRAP_CHANNEL_CAPACITY environment variables to tune the PTY output ring-buffer size and broadcast channel capacity at service startup, replacing hardcoded defaults.

Changes

  • PtyBackend::new_with_config(prefix, channel_capacity, max_history_bytes) constructor stores and threads config into every PtyOutputStream
  • PtyBackend::new() retains default behaviour (DEFAULT_HISTORY_BYTES / DEFAULT_CHANNEL_CAPACITY)
  • main.rs reads both env vars at startup (PTY backend only) and logs the resolved values
  • Doc comment in main.rs updated to list the new env vars
  • Two new unit tests: pty_backend_new_uses_default_buffer_config and pty_backend_new_with_config_applies_custom_values

Test plan

  • cargo test -p wrap — 135 tests pass
  • cargo clippy -p wrap -- -D warnings — clean
  • cargo fmt --check -p wrap — clean
  • AGENTD_BACKEND=pty AGENTD_WRAP_HISTORY_BYTES=1048576 AGENTD_WRAP_CHANNEL_CAPACITY=512 logs resolved values on startup

Closes #1164

🤖 Generated with Claude Code

@geoffjay geoffjay added the review-agent Used to invoke a review by an agent tracking this label label Apr 17, 2026
Copy link
Copy Markdown
Owner Author

@geoffjay geoffjay left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: feat(wrap) — PTY ring-buffer configurable via env vars

Stack position: Standalone — branches directly off feature/autonomous-pipeline (confirmed via git-spice log short). No parent PR to review first.


🔴 Blocking — zero-capacity panic on AGENTD_WRAP_CHANNEL_CAPACITY=0

tokio::sync::broadcast::channel panics when capacity is 0 (documented requirement: capacity ≥ 1). The current parsing chain:

let channel_capacity = env::var("AGENTD_WRAP_CHANNEL_CAPACITY")
    .ok()
    .and_then(|v| v.parse::<usize>().ok())
    .unwrap_or(DEFAULT_CHANNEL_CAPACITY);

...does not protect against 0. parse::<usize>().ok() returns Some(0) for the string "0", so unwrap_or is never reached. The 0 flows through PtyBackend::new_with_configPtyOutputStream::newbroadcast::channel(0) at pty_stream.rs:108. The service panics on the first call to create_session, not at startup — making it a silent runtime trap.

Fix — fail loudly at startup (preferred; matches how DockerBackend misconfiguration is handled in the same file):

let channel_capacity = env::var("AGENTD_WRAP_CHANNEL_CAPACITY")
    .ok()
    .and_then(|v| v.parse::<usize>().ok())
    .unwrap_or(DEFAULT_CHANNEL_CAPACITY);
if channel_capacity == 0 {
    anyhow::bail!("AGENTD_WRAP_CHANNEL_CAPACITY must be at least 1 (broadcast::channel panics on 0)");
}

Or clamp silently with .map(|v| v.max(1)) before unwrap_or if silent recovery is preferred.

Note: AGENTD_WRAP_HISTORY_BYTES=0 is safe — the ring buffer degrades to no-replay without panicking.

Also needs a test — e.g., verify that new_with_config("t", 0, 1024) either panics-with-message or is rejected before construction reaches PtyOutputStream::new.


🟡 Non-blocking — orchestrator binary uses PtyBackend::new() with hardcoded defaults

crates/orchestrator/src/main.rs:103 also constructs PtyBackend when AGENTD_BACKEND=pty:

Arc::new(PtyBackend::new("agentd-orch"))  // still uses hardcoded defaults

Setting AGENTD_WRAP_HISTORY_BYTES / AGENTD_WRAP_CHANNEL_CAPACITY has no effect on the orchestrator's PTY backend. If this is intentional scope, update the doc comments to say "wrap service only". Otherwise, file a follow-up issue — don't expand scope here.


🟡 Non-blocking — silent fallback for unparseable env var values

AGENTD_WRAP_HISTORY_BYTES=2gb silently falls to the default with no log output. A tracing::warn! on the None branch would help operators debug misconfiguration. Easy to add alongside the fix above.


✅ Everything else looks correct

  • new_with_config cleanly delegates from new() — backward compat preserved, all existing tests unaffected.
  • Private fields accessed from within mod tests { use super::*; } — idiomatic Rust.
  • Env var reading scoped to the PTY match arm only — Docker, Tmux, Subprocess unaffected.
  • Doc comments in main.rs and pty.rs are accurate and well-placed.
  • Two new unit tests correctly exercise both construction paths.
  • Diff is tightly scoped — zero unrelated changes.

Comment thread crates/wrap/src/main.rs Outdated
let channel_capacity = env::var("AGENTD_WRAP_CHANNEL_CAPACITY")
.ok()
.and_then(|v| v.parse::<usize>().ok())
.unwrap_or(DEFAULT_CHANNEL_CAPACITY);
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Blocking: broadcast::channel(0) panics. parse::<usize>().ok() returns Some(0) for "0" so unwrap_or is never reached — the zero flows to pty_stream.rs:108 and panics on first create_session call.

Fix:

.and_then(|v| v.parse::<usize>().ok())
.map(|v| v.max(1))                      // broadcast::channel(0) panics; clamp to ≥ 1
.unwrap_or(DEFAULT_CHANNEL_CAPACITY);

Or fail at startup with anyhow::bail!("AGENTD_WRAP_CHANNEL_CAPACITY must be at least 1").

@geoffjay geoffjay added needs-rework PR has review feedback that must be addressed before merging and removed review-agent Used to invoke a review by an agent tracking this label labels Apr 17, 2026
…eview feedback)

- Clamp AGENTD_WRAP_CHANNEL_CAPACITY to ≥ 1 with a tracing::warn\! (broadcast::channel(0) panics)
- Add defensive assert in PtyBackend::new_with_config with a clear message
- Add should_panic test: pty_backend_new_with_config_zero_capacity_panics
- Emit tracing::warn\! when either env var is set to an unparseable value
- Clarify doc comments: these env vars apply to agentd-wrap service only

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@geoffjay geoffjay added the review-agent Used to invoke a review by an agent tracking this label label Apr 17, 2026
@geoffjay
Copy link
Copy Markdown
Owner Author

geoffjay commented Apr 18, 2026

This change is part of the following stack:

Change managed by git-spice.

@geoffjay geoffjay merged commit 116a628 into main Apr 18, 2026
5 of 12 checks passed
@geoffjay geoffjay deleted the issue-1164 branch April 18, 2026 05:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-rework PR has review feedback that must be addressed before merging review-agent Used to invoke a review by an agent tracking this label

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Make wrap service output ring buffer configurable

1 participant