Skip to content

Design: the request interface should not force everything into verbs (verbs vs resources vs subscriptions vs services) #373

Description

@ohdearquant

Summary

Today every capability is modeled as a verb dispatched through the single request tool (ADR-016) over a flat, pack-declared verb registry (ADR-023). That uniformity was the right call for the request/response KG surface. As the system grows transports, channels, and background concerns, the "everything is a verb" model is being stretched to cover things that are not request/response operations. This issue opens a design discussion (→ ADR) on a richer interface taxonomy. Not a v1 change.

Why now

The email channel work is the trigger. Two capabilities it needs do not fit a verb:

  • Background services. The IMAP inbound poll loop and the new outbound delivery loop are long-running daemons, not caller-invoked verbs. They live in the server binary (khive-mcp/src/serve.rs), bolted on outside the verb registry, started by ad-hoc feature-gated spawn code. A pack cannot declare "I own a background service" today.
  • Push / subscription. There is no primitive to subscribe to an event such as "a new inbound message arrived." Consumers poll instead — the canonical inbox wake-up monitor is a MAX(created_at) SQLite poll precisely because there is no push/stream shape on the interface.

Related, already-visible seams:

  • Internal-only subhandlers (e.g. comm.ingest) already form a second class of "verbs that are not user-facing verbs." A flat verb surface that quietly contains off-wire entries is a sign the single taxonomy is conflating distinct kinds.
  • Reads vs actions. MCP itself distinguishes tools (actions) from resources (addressable reads). Pure reads (get, list, stats) are natural resources; mutations are natural verbs. We model both as verbs.
  • Batch semantics. request batches verbs with no inter-op ordering or atomicity guarantee — fine for independent reads, ambiguous for anything transactional.

Direction (for discussion, nothing decided)

A capability taxonomy instead of one flat verb list. Candidate kinds:

  • verbs — request/response actions (the current surface; keep it)
  • resources — addressable reads, possibly mapped to MCP resources
  • subscriptions / streams — push for events (inbound message, task transition, …)
  • services — long-running background daemons, declared by a pack and supervised by the runtime, rather than hand-spawned in the server binary
  • internal subhandlers — off-wire, explicitly second-class (formalize what comm.ingest already is)

Open questions

  1. Should packs declare background services and subscriptions as first-class, with the runtime supervising lifecycle, replacing the serve.rs bolt-on?
  2. Should pure reads migrate to MCP resources, or stay verbs for one uniform surface?
  3. How does any of this interact with ADR-016 (request DSL) and ADR-023 (declarative pack format) — additive layer, or a revision?
  4. What is the backward-compatibility path? The flat verb surface is a public contract.

Scope

Design discussion → ADR. Down the road, not blocking current channel work. Cross-refs: the channel transport work and the multi-tenant/multi-provider channel design discussion.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions