waiting-on

waiting-on

Provides an MCP server that tracks open loops (pending decisions or replies) across email, agent sessions, and other channels, enabling agents to query what is waiting on whom.

Category
Visit Server

README

waiting-on

A local-first, tenant-separated open-loops ledger for agentic workflows: it tracks who has the ball, per domain, across email, agent sessions, and other channels.

An "open loop" is anything waiting on a decision or a reply. waiting-on reads the places those loops accumulate (an email account, your Claude Code and Codex session transcripts, a voice queue, manually entered leads), normalizes each one to a single record type, and stores it in a per-domain local SQLite database. It then answers one question from several surfaces: what is still waiting on you, and what are you waiting on someone else for.

The ledger core reads and tunes your data; it never sends anything. The one write it can make to an outside system is an explicit, opt-in draft-creation tool: waiting_on_draft_reply (and its draft --create-gmail-draft CLI equivalent) can create a Gmail draft through an external Gmail MCP server, and that is the only write path off the local store. There is no send path anywhere in the code. waiting-on holds no credentials of its own and stores snippets rather than full message bodies.

Why it is built this way

The interesting parts are the guarantees, not the CRUD.

  • Fail-closed tenant walls. Each domain maps to its own SQLite database file, with a fail-closed profile allow-list enforced in application code (the Ledger facade), not an OS-level sandbox. A session runs under a profile that names the domains it may open; an unknown or unmapped profile resolves to no domains rather than to everything. The Ledger facade raises TenantWallError when a caller reaches for a domain outside its profile, and AmbiguousDomainError when a bare line_id exists in more than one allowed domain, so it refuses to guess which tenant you meant instead of silently writing the wrong one.

  • Optimistic-concurrency writes with named failure modes. Lead writes are versioned compare-and-swap operations against a WAL-mode database. A losing write raises LeadWriteConflict, and a lock-contention retry-exhaustion raises LeadWriteBusy (a subclass). The failure each one guards against is spelled out in its docstring, for example a completed lead being silently reopened by a stale writer.

  • Pluggable adapters over one contract. Email, agent-threads, voice, and manual-lead collectors each normalize their source into a single LineObservation. Adding a channel means writing one adapter, not touching the ledger. The deterministic file-based collectors (agent-threads, voice, manual leads) degrade to empty results when their source is absent: they yield nothing rather than raising. The email path is the exception: it shells out to an external Gmail MCP server, and a failure of that subprocess surfaces as a GmailMcpError rather than being swallowed.

  • Deterministic core, zero-LLM collectors. The agent-threads and voice adapters classify state with deterministic heuristics and replay, not a model call, so their output is reproducible and testable. An injected clock makes all age math deterministic under test.

  • Four surfaces over one ledger. An MCP server (for agent tool use), a CLI, an fzf-driven tuning TUI, and a static self-contained HTML board all read the same store.

The test suite covers the tenant walls, the concurrency failure modes, each adapter's normalization and fail-soft behavior, and the render surfaces. Run it with python3 -m pytest from the repo root; it is 156 tests today.

Architecture

email account         -> GmailMcpClient       -+
Claude/Codex sessions -> AgentThreadsAdapter   -+-> LineObservation -> per-domain
voice queue (JSONL)   -> VoiceAdapter          -+     (one contract)     SQLite DB
manual leads (JSON)   -> ManualLeadAdapter     -+                            |
                                                                            v
                                        MCP server | CLI | TUI | HTML board

The tenant boundary is enforced where roots and accounts resolve to a domain, so an adapter can only ever read the sources authorized for the domain it is collecting.

Install

Requires Python 3.11 or newer. No required third-party dependencies for the core.

python3 -m pip install -e .

Optional extras: .[mcp] for the MCP server, .[parquet] for Parquet export. The tuning TUI additionally needs textual, and the fzf TUI needs fzf.

You can also run straight from a checkout without installing, via the launchers in bin/.

Quickstart

The repository ships a synthetic examples/demo-leads.json so you can see the shape without any configuration. With no config file, waiting-on uses a single default domain.

# Import the demo leads into the local ledger
bin/waiting-on lead seed examples/demo-leads.json

# See who has the ball (your side first)
bin/waiting-on lead list

# A compact open-loops pane, suitable for a terminal or a cmux column
bin/waiting-on pane

# Render a static, self-contained HTML board from the current leads
python3 scripts/render_lead_board.py --out board.html

To wire up real sources (email accounts, agent-session roots, domains, and profiles), copy config.example.toml to ~/.config/waiting-on/config.toml and edit it. The example file documents the tenant-wall and profile model inline.

Documentation

  • docs/open-loops-ledger-design.md: the design and phased plan, including the tenant-wall model.
  • docs/agent-threads-adapter-spec.md: how the agent-session collector decides a session is a forgotten open loop.
  • docs/cli-contract.md: the machine-readable CLI contract and exit codes.
  • docs/security.md: what is and is not stored, and why there is no send path.
  • docs/studio-spec.md and docs/calibration-and-panes.md: the TUI and the live-tuning panes.
  • docs/agent-integration.md: driving waiting-on from an agent.

Status

Early and actively developed: this repository was extracted from a working personal deployment, so the interfaces are real but may still shift, and the demo leads shipped here are synthetic.

Known rough edges:

  • The agent-threads classifier is a deterministic tail heuristic over transcript events. It is conservative and tunable (idle-hours and max-age dials), but it can still misjudge an unusual session; treat its waiting_on_me calls as strong hints, not verdicts.
  • The email adapter expects an external Gmail MCP server to be configured (its command is set in config). waiting-on deliberately does not hold Gmail credentials itself, so email refresh does nothing until that is wired up.
  • Additional channels (for example iMessage) and an optional LLM enrichment pass are described in the design doc but not yet built. Today the collectors are deterministic and zero-LLM.
  • The config example is intentionally minimal. Multi-domain setups work, but you configure the domains, accounts, and profiles by hand.

License

MIT. See LICENSE.

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured