Agent Teams inbox polling doesn't work in non-interactive/SDK streaming mode

Status Closed — not planned
Reported on v2.1.44
Maintainer reply None cached
Activity 11 comments · opened Feb 17, 2026 · closed Mar 29, 2026

Description

Agent Teams inbox-based messaging does not work when Claude Code runs in non-interactive mode (e.g., via the SDK with --output-format stream-json and stdio: pipe). The InboxPoller is implemented as a React UI hook (setInterval every 1000ms) that only fires when the React TUI renders — which requires an interactive TTY.

Steps to Reproduce

  1. Use the Claude Code SDK (or any wrapper that spawns Claude Code with stdio: ['pipe', 'pipe', 'pipe'])
  2. Enable Agent Teams (CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1)
  3. Have the lead agent spawn teammates via TeamCreate + Task
  4. Teammates complete their work and send messages to the lead's inbox
  5. Lead never receives the messages — the inbox JSON files are written but never read

Expected Behavior

The lead agent should receive teammate messages regardless of whether it's running in interactive (TTY) or non-interactive (pipe/SDK) mode.

Actual Behavior

  • From terminal (interactive, TTY): Works perfectly. InboxPoller React hook fires every second, reads inbox JSON files, and delivers messages.
  • From SDK/non-interactive mode: InboxPoller never fires because the React TUI doesn't render. Inbox JSON files accumulate but are never read. The lead agent hangs waiting for teammate responses that never arrive.

Root Cause Analysis

The non-interactive detection logic:

let z = A.includes("-p") || A.includes("--print") || A.includes("--init-only") || A.some($ => $.startsWith("--sdk-url")) || !process.stdout.isTTY;

When process.stdout.isTTY is false (pipe mode), Claude Code enters non-interactive mode → React TUI doesn't render → InboxPoller hook (setInterval) never fires → inbox messages are never delivered.

Suggested Fix

Add a non-UI inbox polling mechanism for non-interactive mode. For example:

  • A simple setInterval in the main process (not tied to React) that reads inbox files when isInteractive === false and Agent Teams are enabled
  • Or expose an environment variable / CLI flag to force inbox polling regardless of interactivity

Environment

  • Claude Code version: 2.1.44 / 2.1.45
  • OS: Ubuntu Linux 6.8.0-90-generic
  • Context: Using Claude Code via Happy app which spawns Claude Code with --output-format stream-json and piped stdio

Workaround

Currently using an external Python script that polls the inbox JSON files directly (~/.claude/teams/{name}/inboxes/{agent}.json), implements debounce, and marks messages as read. This works but is fragile and shouldn't be necessary.

Related Issues

  • #23415 - Agent teams message delivery
  • #23620 - Agent teams coordination
  • #24108 - Agent teams in non-interactive contexts

View original on GitHub ↗

11 Comments

github-actions[bot] · 6 months ago

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/23415
  2. https://github.com/anthropics/claude-code/issues/23874
  3. https://github.com/anthropics/claude-code/issues/26244

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

lifeofzero · 6 months ago

@dudu1111685 does your work around wake the lead back up or is it still "asleep"?

dudu1111685 · 6 months ago

The workaround does wake the lead back up. The approach: in CLAUDE.md (the rules file Claude Code loads automatically), the lead is instructed to run the polling script and wait for its output. When a new inbox message arrives, the script writes it to stdout — so the lead is actively blocking on the script's output and resumes immediately when a message is delivered. It's not polling on the Claude side; it's just waiting for the script to surface the message.

ThinkOffApp · 6 months ago

Ran into the same wall. We needed agents to coordinate without relying on the TUI render loop, especially since half our fleet runs headless via tmux.

We ended up sidestepping the inbox entirely and using a webhook relay - external service pushes tasks into a queue, a shell script polls it, and the agent picks up work through file watches. Crude compared to proper inbox polling but it works in non-interactive mode without patching Claude Code internals. Open sourced it as ide-agent-kit if anyone wants to look at the approach.

Are you running the SDK wrapper as a long-lived process or spawning fresh per task? Curious whether a filesystem-based message bus would work for your setup.

lifeofzero · 6 months ago

We're running headless claude claude -p in a long-lived process (15-25 minutes). I ended up disabling agent teams for the time being and will go back to it when they've fixed this issue.

I'll definitely have a look at your approach. A filesystem-based message bus would work for us.

ThinkOffApp · 6 months ago

Nice - 15-25 minute headless runs are exactly what we're doing too. The filesystem bus is dead simple: agent writes a JSON task to an inbox dir, a watcher picks it up, routes it to the right tmux pane, and the receiving agent reads it as a file change. No sockets, no polling loop inside Claude, just inotify/fswatch.

The scripts/poll-tasks.sh in the repo does the heavy lifting. You'd point it at a shared directory and it'll fan out to however many agents you have running. We run 6 agents across two machines and it's been solid.

One thing that tripped us up early: make sure you set a reasonable poll interval (we use 5s) otherwise you'll burn CPU on the watcher. Happy to help if you hit any snags setting it up.

dudu1111685 · 6 months ago

I am using this for happy so they's no tmux...

ThinkOffApp · 6 months ago

Interesting - what are you using instead of tmux for the session management? We found that once you drop the tmux dependency the coordination gets simpler since you're not fighting terminal state.

ThinkOffApp · 6 months ago

For anyone still hitting this — we formalized the filesystem polling approach into IDE Agent Kit v0.3.1. It handles the headless coordination case end to end: file-based notification delivery, seen-ID tracking, and automation rules that nudge agents when new work arrives.

Works without tmux too — the core is just a JSONL queue and a poller. Happy to help anyone get set up.

github-actions[bot] · 5 months ago

Closing for now — inactive for too long. Please open a new issue if this is still relevant.

github-actions[bot] · 4 months ago

This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.