The k9s for AI Agents: Unpacking Tempo

How a React-driven terminal dashboard uses direct SQLite introspection to orchestrate parallel AI coding sessions.

6 min read • View on GitHub • More from roerohan

A classic 1920s telephone switchboard operated by mechanical robotic arms plugging glowing cables into a grid. This illustrates Tempo's role in managing and routing dozens of simultaneous AI agent connections.
Tempo serves as a central multiplexer for parallel agentic workflows.
Key Takeaways

The Swarm Bottleneck

We moved from chatting with single AI assistants to dispatching multiple autonomous agents in parallel. One agent refactors, another writes tests, a third scours documentation. The terminal quickly becomes a chaotic bottleneck.

When running multiple instances of tools like opencode, developers lose track of which agent is working, which is stalled awaiting input, and which has finished. Tempo acts as a centralized command center to solve this context-switching penalty.

Standard Agent CLITempo Dashboard
Sequential executionParallel execution monitoring
Blind to background tasksVisual status indicators (pending/working)
Manual process backgrounding (ctrl+z)One-keystroke session switching
State is hidden behind APIState is extracted via direct DB queries

Bypassing the API

The standard opencode CLI does not expose real-time granular states in a list view. Tempo bypasses the official CLI entirely. It queries the underlying opencode.db SQLite file directly.

Using complex json_extract calls, Tempo parses internal states in real-time. It knows exactly when a session is working or pending user input. It includes a fallback mechanism that reverts to the standard CLI if the SQLite query fails, ensuring resilience against schema changes.

Tempo bypasses the limited CLI abstraction to achieve real-time status monitoring by directly reading the database.

React as a System Dispatcher

Building a CLI tool with a web framework sounds counterintuitive. Tempo uses the Ink library to render React components in the terminal. This allows the developer to construct complex, stateful system tools using familiar frontend patterns.

A heavy industrial brass gear mechanism with a sleek modern silicon microchip embedded directly into the center axis. This represents using a high-level web framework like React to orchestrate low-level system processes.
React (the microchip) orchestrates raw terminal and OS processes (the heavy machinery).

The architecture relies on an Unmount-Remount pattern. Tempo entirely unmounts its React tree to hand over raw terminal control to a spawned child process. When the user exits the session, the dashboard successfully remounts.

async function startApp() {
  const { waitUntilExit } = render(<App />);
  await waitUntilExit();
  // Wait for child process to finish, then remount
  if (shouldRestart) {
    startApp();
  }
}

State Machines and Vim Constraints

Developer ergonomics dictate whether a CLI tool survives its first week. Tempo implements native Vim bindings embedded directly within React components. Users navigate with j, k, gg, and G.

It uses TypeScript Discriminated Unions to manage application state. By defining modes like ModeFiltering and ModeConfirmDelete, the developer prevents impossible UI states. You cannot filter and delete simultaneously.