Skip to content

Proposal: paradigm-aware plugin surfaces via kind: driver + paradigms #381

Description

@NewtTheWolf

Proposal: paradigm-aware plugin surfaces via kind: driver + paradigms

Depends on #306 (Decoupling RFC). This builds on the standardized driver /
capability contract from that RFC and should land after it. The work below is
intentionally broad — when picked up it should be split into the subtasks outlined
in Work breakdown.

Problem

Today every connector is modeled relationally: databases → tables → columns → SQL execute_query → QueryResult. Non-relational engines — search engines, document
stores, key-value, vector — don't fit this shape and have to emulate it:

  • QueryResult.affected_rows / pagination are SQL/DML artifacts these engines
    don't have.
  • execute_query expects SQL, so flat stores fake it (e.g. SELECT * FROM x to
    list documents) and silently ignore filters and projection.
  • The connection model assumes a set of selectable databases that some engines
    don't have at all.
  • Their real query model — ranked search, facets, field filters — has nowhere to
    live, because the host only offers the SQL grid and editor.

The root cause is that the host has a single interaction surface, but different
engines have different primary verbs: a document store filters-and-gets, a
search engine searches-and-ranks, a key-value store gets-and-sets. One UI can't
serve all of them well, and bending each engine to fit the SQL surface produces the
friction above.

Proposal

kind should describe the plugin type, not the data model. Every connector
installs the same way (a binary speaking JSON-RPC over stdio) and follows the same
lifecycle, so they all stay kind: driver. The differences between engines belong on
finer axes:

kind: driver           # stable: "it's a driver"
  └─ paradigms[]        # primary verb → host picks the surface
  └─ capabilities{}     # feature flags within the driver contract
  └─ optional methods   # search() / facets() / query(filter) → unlock richer UI
  └─ ui_extensions[]    # paradigm-specific panels via slots
  1. paradigms[0] is the primary verb, and it selects which surface the host
    shows for a connection. Paradigms are admin-managed facets, so introducing a new
    data model needs no schema release — just a new facet value.

  2. Optional RPC methods are the actual unlock. A paradigm is only a hint; the
    host renders a richer surface for a connection when the driver actually implements
    the matching methods (e.g. search() for a search engine), and falls back to the
    standard grid when it doesn't. This keeps it honest — a plugin can't claim a
    paradigm it doesn't back — and lets engines adopt the new surface incrementally
    (progressive enhancement, graceful degrade).

  3. Surfaces are built into core and shown contextually, i.e. rendered only when
    an open connection's paradigm matches. The code ships with the app, but a search
    panel never appears unless you've opened a search connection. The SQL grid remains
    the default and the universal fallback. We'd start with two surfaces that cover the
    most engines: search (Meilisearch, Typesense, Elasticsearch) and document
    (Firestore, MongoDB).

  4. One surface per paradigm — no single "NoSQL" surface. "NoSQL" lumps together
    incompatible verbs (document ≠ search ≠ key-value ≠ graph); each needs its own UI.

// document store
"kind": "driver", "paradigms": ["document"]
// search engine
"kind": "driver", "paradigms": ["search", "document", "vector"]

How it fits together

manifest: kind=driver, paradigms=[search,…]
        │
        ▼
host resolves surface for a connection:
   paradigms[0]  +  which optional methods the driver implements
        │
        ├─ implements search()/facets()  → Search surface
        ├─ implements query(filter)/CRUD → Document surface
        └─ neither                        → SQL grid (fallback, unchanged)

The relational path is untouched: existing SQL drivers declare no extra paradigm or
methods and keep the grid. New surfaces are additive.

Work breakdown

When this is scheduled, split into the following subtasks. Groups are roughly
ordered; A–C are prerequisites for the surfaces in D–E.

A. Contract (backend / spec)

  • Define the optional RPC method set per paradigm and their result shapes:
    search(index, q, filter, facets, sort), facets(index), and
    query(collection, filter, sort, page) for document.
  • Decide how the host learns which optional methods a driver supports
    (capability flags vs. JSON-RPC method not found probing).
  • Write the contract reference in the plugin author docs.

B. Registry / metadata

  • Ensure the paradigm facets exist (search, document, vector,
    key-value, graph) and are documented.
  • Document paradigms ordering semantics ([0] = primary).

C. Host: surface resolution

  • Resolve a connection to a surface from paradigms[0] + implemented methods.
  • Grid fallback when no surface matches or methods are missing.
  • Scaffold a view switcher for multi-paradigm engines (used in D/E).

D. Search surface

  • Query box → ranked results with score, wired to search().
  • Facet panel from facets() / filterable fields; filter + sort controls.
  • Document/result viewer (JSON) and per-result actions.
  • Index list + settings view (optional, can be a follow-up subtask).

E. Document surface

  • Collection/namespace browser (incl. hierarchy where applicable).
  • Filter builder (field op value, composite) → query(collection, filter).
  • Document JSON viewer/editor with CRUD.

F. Reference drivers / migration

  • Migrate one search driver and one document driver to the contract.
  • Remove any UI-extension/grid workarounds those drivers used to fake a surface.

G. Docs & examples

  • Plugin author guide: declaring a paradigm and implementing the optional
    methods, with a minimal example per surface.
  • User-facing docs for the new surfaces.

Scope

In scope: the model above and the first two surfaces (search, document), plus the
contract and host wiring they need.

Out of scope for now:

  • A second plugin framework or a separate kind per data model.
  • Replacing the SQL grid — it stays the default and the fallback.
  • Per-database UIs — surfaces are generic per paradigm.
  • Long-tail paradigms (key-value, graph, time-series) and full vector UIs. They can
    follow later, and could even ship as community surface plugins once the extension
    API supports full custom views.

Open questions

  • Method signatures and result shapes per paradigm — the filter model, facet
    response, ranking score field.
  • How a multi-paradigm engine (e.g. search + document + vector) exposes its
    secondary surfaces: a view switcher, or primary-only?
  • Whether vector search is its own paradigm and surface, or a mode inside the search
    surface.
  • Capability flags vs. method probing for detecting optional-method support.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions