From Agent Roster to Worker Pool: Refactoring UI for Scalable Agent Orchestration
The Problem with the Old AgentRoster
A few weeks ago, the Agent Orchestrator dashboard still relied on a single, bloated AgentRoster component to manage all agent workers. It was built early in the project’s life—quick, functional, and already out of its depth. As we rolled out specialist agents for tasks like memory indexing, workflow routing, and external API polling, the AgentRoster became a bottleneck. It rendered every agent the same way, regardless of role, and handled state locally within deeply nested child components. That made it impossible to scale.
Worse, syncing dynamic states—like whether a worker was idle, processing, or stuck in a retry loop—meant prop-drilling through four levels of components or leaning on global state too early. We were trading short-term convenience for long-term fragility. The final straw? Trying to integrate real-time status updates from our new cron-triggered jobs and ChromaDB memory search agents. The UI couldn’t keep up.
We needed a shift: from a flat list of agents to a structured, role-aware worker pool system that could grow with our backend.
Enter the WorkerPoolPanel: A Modular Upgrade
On February 4th, 2026, I merged the refactor that replaced AgentRoster with WorkerPoolPanel—a new React component designed around separation of concerns and scalable state management. The key was state lifting and role-based composition.
Instead of each agent managing its own status, WorkerPoolPanel now owns the worker state at the container level. It pulls agent data from a centralized service (via a custom hook, useWorkerPool), then distributes it down to role-specific subcomponents: IndexingWorkerCard, CronWorkerCard, RouterWorkerCard, etc. Each card knows how to render and interact with its agent type, but none of them own the state. This made rendering dynamic statuses—like a worker warming up or syncing memory—cleaner and more predictable.
We also introduced a workerRole enum that maps agent types to UI behavior. That means when a new specialist agent is added (say, a "validation worker" for PaidFor’s transaction pipeline), the dashboard automatically renders the right controls and status indicators—no UI fork needed.
But the real win was composability. WorkerPoolPanel can now be embedded in multiple views: the main dashboard, a workflow debug panel, even a minimized status bar in the Git Context tool. It’s not just a replacement—it’s a reusable primitive.
Enabling Backend Integration (Without Breaking the Frontend)
The refactor wasn’t just about cleaner code—it unlocked backend features that were previously too awkward to wire in. Two in particular stand out.
First: ChromaDB memory search integration. Our new memory-aware agents periodically index workflow context into ChromaDB. Before the refactor, showing their sync status meant hacking state into AgentRoster via side effects. Now, WorkerPoolPanel listens to a WebSocket feed and updates the IndexingWorkerCard in real time. Users see exactly when memory is stale, syncing, or ready—no refresh needed.
Second: Cron job controls. We’re rolling out time-triggered agent workflows, and operators need to pause, resume, or trigger jobs manually. The old UI had no concept of schedulable workers. With WorkerPoolPanel, we added a useCronControls hook that exposes play/pause buttons only for agents with a cronSchedule property. The UI adapts. The backend stays decoupled.
This wasn’t a rewrite—it was a strategic pivot. By treating agents as role-based workers in a shared pool, we aligned the frontend with the backend’s evolving architecture. And because the component is now modular, we can A/B test new agent types, add telemetry, or even open-source the panel without exposing internal logic.
Looking back at those 10 commits from that day, it’s clear: the biggest wins in UI aren’t always flashy. Sometimes, it’s just about building the right container for the work that’s coming.