Skip to content

feat: inbox YAML archiving + nudge cooldown to reduce redundant token cost#170

Open
Rusty-Alucard wants to merge 2 commits into
yohey-w:mainfrom
Rusty-Alucard:feat/inbox-archive-nudge-cooldown
Open

feat: inbox YAML archiving + nudge cooldown to reduce redundant token cost#170
Rusty-Alucard wants to merge 2 commits into
yohey-w:mainfrom
Rusty-Alucard:feat/inbox-archive-nudge-cooldown

Conversation

@Rusty-Alucard

Copy link
Copy Markdown
Contributor

Background

This PR addresses a token efficiency problem identified via Idiot Index reasoning:

Idiot Index = actual cost ÷ minimum necessary cost

Before this change, inbox_watcher.sh reads the full inbox YAML on every processing cycle. As agents accumulate message history, the inbox grows to 50KB+ — but the minimum necessary information per cycle is only the unread message bytes (typically <1KB). This produces an Idiot Index of 50–134×.

Changes

Inbox YAML Archiving (INBOX_ARCHIVE_ENABLED=1, INBOX_ARCHIVE_KEEP_READ=20)

  • New archive_read_messages() function moves excess read messages to queue/inbox/archive/{agent}.yaml
  • Keeps at most INBOX_ARCHIVE_KEEP_READ (default: 20) read messages in the active inbox YAML
  • Called when the inbox is fully processed (all messages read)
  • Append-only archive file — full message history is preserved, just moved out of the hot path
  • Env vars are fully configurable; set INBOX_ARCHIVE_ENABLED=0 to disable

Nudge Absolute Cooldown (NUDGE_MIN_INTERVAL_SEC=30)

  • Adds a 30-second absolute minimum interval between any nudge, regardless of unread count changes
  • Prevents nudge spam when multiple follow-up messages arrive in rapid succession
  • Phase 3 /clear escalation uses send_cli_command directly and is not affected by this throttle

Metrics Accuracy (unread bytes)

  • get_unread_info() now returns unread_bytes: the actual byte size of unread message content
  • update_metrics() uses unread_bytes instead of the full inbox file size
  • Token estimates now reflect actual processing cost, not accumulated file bloat

Before / After

Metric Before After (estimated)
commander inbox per read ~46KB ~11KB (−76%)
strategist inbox per read ~19KB ~8KB (−58%)
Metrics accuracy full file size unread bytes only

Actual after-values depend on archive trigger (>20 read messages). Estimates based on current inbox sizes with 41/38 messages respectively.

Safety

All existing resilience measures are preserved:

  1. Zero message loss: unread guard (SKIP_HAS_UNREAD) prevents archiving when any unread message exists
  2. Deadlock prevention: stale busy safety net (5-minute force-idle) unchanged
  3. Final escalation (/clear path, Phase 3) unchanged
  4. Lock safety: archive_read_messages() uses the same acquire_inbox_lock / release_inbox_lock pattern as existing code
  5. Append-only archive: archived messages are never deleted
  6. Configurable: all new features controlled by env vars, defaults to enabled
  7. No breaking changes: existing behavior unchanged when inbox is below threshold

Testing

  • Existing unit tests in tests/unit/test_send_wakeup.bats pass with no new failures
  • __INBOX_WATCHER_TESTING__=1 mode unchanged (archive function loads correctly)
  • 6 pre-existing test failures (unrelated features: antigravity CLI, OpenCode /model, legend-leader display-message) are unchanged

🤖 Generated with Claude Code

kamiya and others added 2 commits June 25, 2026 14:13
… cost

Problem (Idiot Index reasoning):
  - Before: inbox_watcher reads the full inbox YAML on every cycle
  - Inbox accumulates hundreds of read messages → 50KB+ per read
  - Minimum necessary: only unread message bytes (typically <1KB)
  - Idiot Index ≈ 50–134× overread per cycle

Changes:
  inbox archiving (INBOX_ARCHIVE_ENABLED=1, INBOX_ARCHIVE_KEEP_READ=20):
  - archive_read_messages() moves excess read messages to queue/inbox/archive/{agent}.yaml
  - Keeps at most 20 read messages in the active inbox YAML
  - Safety: unread messages are NEVER archived (SKIP_HAS_UNREAD guard)
  - Append-only archive file preserves full history

  nudge absolute cooldown (NUDGE_MIN_INTERVAL_SEC=30):
  - Prevents nudge spam when follow-up messages arrive in rapid succession
  - Guards before the per-count cooldown check
  - Phase 3 /clear uses send_cli_command directly — not affected

  metrics accuracy (unread_bytes):
  - get_unread_info() now returns unread_bytes (actual bytes of unread content)
  - update_metrics() uses unread_bytes instead of full file size
  - Token estimates now reflect actual processing cost, not file bloat

Safety measures preserved:
  - Zero message loss: unread guard before any archive operation
  - Deadlock prevention: stale busy safety net unchanged
  - Final escalation (/clear path) unchanged
  - All 7 resilience invariants maintained

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
`flock` is not available on macOS by default. Added `command -v flock`
guard with mkdir-based fallback (same pattern as inbox_watcher.sh
lines 312/416/518). Linux behavior is unchanged.

Fixes macOS Unit Tests CI failure in PR yohey-w#170.
@Rusty-Alucard

Copy link
Copy Markdown
Contributor Author

Also fixes pre-existing macOS incompatibility in watcher_supervisor.sh:
flock is not available on macOS by default. Added command -v flock guard
with mkdir-based fallback (same pattern as inbox_watcher.sh lines 312/416/518).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant