← Back to PRs

#8427: [FEATURE] feat(spool): add spool event dispatch system with shared agent turn infrastructure

by mcaxtr open 2026-02-04 01:31 View on GitHub →
gateway cli agents size: XL trusted-contributor experienced-contributor
## Summary Adds the **spool event dispatch system** — a file-based queue for running agent turns asynchronously with retry logic, expiration, and dead-letter handling. > **Discussion:** https://github.com/openclaw/openclaw/discussions/12036 ### Why Spool? In multi-agent setups — such as the [Mission Control pattern](https://www.sitegpt.ai/blog/building-mission-control-ai-agent-squad) where 10+ agents collaborate as a team — each agent wakes on a fixed cron schedule (e.g. every 15 minutes) to poll for work. This heartbeat approach has clear limitations: agents burn API credits on empty polls, work sits idle for up to 15 minutes, and nothing survives a gateway restart. The spool system shifts from **polling to event-driven dispatch**: instead of agents asking "is there work?", work is queued and pushed to agents when it arrives. Specifically, the spool enables: - **Async agent execution** — Queue agent turns without blocking - **Reliability** — Automatic retries with configurable limits - **Persistence** — Events survive gateway restarts - **Observability** — Dead-letter queue for failed events ### What's Included **Spool event system** (`src/spool/`) - Event types with priority levels (high/normal/low/background) - File-based persistence with JSON schema validation - Retry logic with configurable max retries and expiration - Dead-letter queue for failed events - Chokidar-based watcher with debouncing **CLI commands** - `spool enqueue` — queue agent turn events - `spool status` — view queue and dead-letter status **Gateway integration** - Spool watcher starts/stops with gateway lifecycle - Processes existing events on startup ### Implementation Detail: Shared Agent Turn Infrastructure To avoid duplicating the ~450-line agent turn execution logic between cron and spool, we extracted it into a shared module (`src/agents/isolated-turn/`). Both cron and spool now use thin wrappers (~60-70 lines each) that convert their source-specific params to a generic `IsolatedAgentTurnParams` interface. ``` src/agents/isolated-turn/ # Shared infrastructure ├── run.ts # runIsolatedAgentTurn() - core logic ├── types.ts # IsolatedAgentTurnSource: "cron" | "spool" └── helpers.ts, session.ts, delivery-target.ts src/cron/isolated-agent/run.ts # Thin wrapper: CronJob → params src/spool/isolated-agent/run.ts # Thin wrapper: SpoolEvent → params ``` ## Test Plan - [x] All existing cron tests pass (52 tests) - [x] New shared isolated-turn tests (19 tests) - [x] New spool tests (68 tests) - [x] Type checking passes (`pnpm tsgo`) - [x] CI checks pass

Most Similar PRs