F8.1 — CLI / MCP / API surface matrix
The single reference for how every hot workflow maps across the three surfaces — CLI (@driftless-sh/cli), MCP (@driftless/mcp), and the API
(@driftless/api) — plus what each read returns by default and how to opt into a
heavier payload.
Read it to answer: “which command/tool/route do these three things share, what
shape comes back, and what is fast by default?”
Conventions:
- Default view is the payload tier a read returns when no
viewis passed (summary/brief/full— seeviews.md).fullis never a default; a caller opts in. - Full-view opt-in is how you ask for the heavy body when you actually need it.
- The MCP names are the literal tool names in
apps/mcp/src/tools/tool-registry.ts; the CLI names are the literal subcommands inapps/cli/src/commands/*; the API rows are the Nest routes underapps/api/src/*(all under/workspaces/:slug).
Topics — read
| Workflow | CLI | MCP tool | API endpoint | Default view | Full-view opt-in | Payload shape |
|---|---|---|---|---|---|---|
| Search by keyword | context search <q> | driftless_context_search | GET /topics/search?q= | summary (top 5 CLI/MCP) | n/a — search is index-only; context_get the hit | { shown, has_more, hint?, next_action, topics[] } |
| List a domain | context list [--area|--tag|--stale] | driftless_context_list | GET /topics | summary (top 40) | view=full | { shown, has_more, hint?, next_action, topics[] } |
| Get one topic | context get <slug> | driftless_context_get | GET /topics/:slug | full (you named it) | default | one CanonicalContext |
| Topics for files | context get --files "a.ts,b.ts" | driftless_context_get_for_files | GET /topics/match-files | brief (top 10, drifted first) | view:"full" | { shown, has_more, hint?, matches[] } |
| Topics for local diff | context get --diff [--mark] | driftless_context_get_for_files (pass the diff file list) | GET /topics/match-files | brief | view:"full" | match-files shape |
| Unified retrieve (task and/or files) | context retrieve "<task>" [--explain] (+ context get --files/--diff for the file-shaped reads) | driftless_context_retrieve | POST /topics/retrieve | brief | view:"full" | { view, total_candidates, signals, shown, results[] } |
match_type / why_matched / confidence /
next_action. The unified ranker is exposed on all three surfaces: CLI
(context retrieve "<task>", --explain for why_matched), API (POST /topics/retrieve), and MCP (driftless_context_retrieve); context get --files/--diff remain the file/diff-shaped reads.
Topics — write & govern
| Workflow | CLI | MCP tool | API endpoint |
|---|---|---|---|
| Create a topic / note | context add <slug> --area --pattern · note add | driftless_context_create · driftless_note_add | POST /topics |
| Update (append-safe) | context update <slug> --gotcha/--decision/--add-pattern | driftless_context_update | PATCH /topics/:slug |
| Propose → Knowledge | context propose <slug> · context approve <slug> | driftless_context_propose · driftless_context_approve | POST /topics/:slug/propose · …/approve |
| Suggested edit | context pr <slug> --open | driftless_context_create_proposal · driftless_context_proposals | POST /topics/:slug/proposals |
| Relations / graph | context relations · context graph | driftless_context_relations · driftless_context_graph | GET /topics/:slug/relations · …/graph |
| Share | context share <slug> | driftless_context_share | POST /topics/:slug/share |
| Delete | context delete <slug> | driftless_context_delete | DELETE /topics/:slug |
| Merge duplicates | context merge <src> --into <dst> | driftless_context_merge | POST /topics/:slug/merge |
| Coverage / doctor / events | context doctor | driftless_context_coverage · driftless_context_doctor · driftless_context_events | GET …/coverage · …/doctor · …/events |
Tags & Areas
| Workflow | CLI | MCP tool | API endpoint |
|---|---|---|---|
| Tags (list / create / delete) | tags [add|rename|rm] | driftless_tags (action) | GET|POST|DELETE /tags |
| Areas (list / create / update / delete) | area [list|add|rename|rm] | driftless_areas (action) | GET|POST|PATCH|DELETE /areas |
Projects — the agent loop
| Workflow | CLI | MCP tool | API endpoint | Default view | Full-view opt-in |
|---|---|---|---|---|---|
| Projects (list / get / set) | project [list|get|add|update] | driftless_project (action) | GET|POST|PATCH /projects | summary | ?view=full |
| Card loop tick | project card next <pid> | driftless_project_card action:next | GET /projects/:id/cards/next | bundle by refs→summary | summaries→brief · full→full |
| Card CRUD / status | project card add|get|status|move|rm | driftless_project_card (action) | …/cards routes | — | — |
next returns { card, context_bundle, project_done } — one call per loop
iteration. The bundle ships the team’s recorded context for the card’s area so the
agent doesn’t re-derive it.
Collections — the operational substrate
| Workflow | CLI | MCP tool | API endpoint | Default view |
|---|---|---|---|---|
| Collections (list / get / add / update) | collection [list|get|add|update] | driftless_collection (action) | GET|POST|PATCH /collections | summary |
| Collection criterion (the seam) | — | driftless_collection action:context | GET /collections/:id/context | criterion topics |
| Collection retrieve (records + criterion, one call) | — | driftless_collection action:retrieve | GET /collections/:id/retrieve | bounded records page + criterion |
| Records (list / get / add / update) | collection record [list|get|add|update] · collection records | driftless_collection_record (action) | …/collections/:id/records | keyset page |
| Entities (list / get / upsert) | — | driftless_entity (action) | GET|POST /entities | — |
collection retrieve is the operational analogue of topic retrieve: relevant
records plus the criterion Knowledge to read before acting, in one GET.
Records paginate by keyset ({ records, nextCursor }).
Integrations (SETUP) vs Broker (EXECUTION)
These are deliberately two separate concerns. Setup connects/configures a provider (the privileged connect flow); the broker only operates a connection that already exists. Authoring/deploying a Nango action is a third, human-only lane that neither surface touches (the no-agent-scripting rule).| Workflow | CLI | MCP tool | API endpoint |
|---|---|---|---|
| SETUP — catalog | integration catalog | — (setup is human-led) | GET /integrations/nango/catalog |
| SETUP — connect | integration connect <provider> | — | POST /integrations/nango/:provider/connect-session |
| SETUP — confirm | integration confirm <provider> | — | POST /integrations/nango/:provider/confirm |
| SETUP — list / disconnect | integration list · integration rm <id> | — | GET /integrations · DELETE /integrations/:id |
| SETUP — guidance | broker setup | — | (prose; no call) |
| EXEC — connections | broker connections | driftless_broker action:connections | GET …/broker/connections |
| EXEC — capabilities | broker capabilities <provider> | driftless_broker action:capabilities | GET …/broker/connections/:provider/capabilities |
| EXEC — operations | broker operations <provider> [--refresh] | driftless_broker action:operations | GET …/broker/connections/:provider/operations |
| EXEC — invoke | broker invoke <provider> <op> --input | driftless_broker action:invoke | POST …/broker/connections/:provider/invoke |
| EXEC — records (synced model) | broker records <provider> --model | driftless_broker action:records | GET …/broker/connections/:provider/records |
| EXEC — page/document content | broker page <id> | driftless_broker action:page-content | GET …/broker/connections/notion/pages/:id/content |
| INDEX — connector document preview | broker index <provider> --dry-run | driftless_broker action:index-preview | POST …/broker/connections/:provider/index/preview |
| INDEX — connector document execute | broker index <provider> | driftless_broker action:index | POST …/broker/connections/:provider/index |
| EXEC — events | broker events [provider] | driftless_broker action:events | GET …/broker/events |
| EXEC — criterion | broker criterion <provider> [--add|--rm] | driftless_broker action:criterion | GET|POST|DELETE …/criterion |
--refresh (CLI) /
refresh:true re-pulls the live list from Nango. Records mirror a synced model and
are delta-aware (--modified-after / cursor). Broker reads and writes both
run inline + audited — Driftless is a tooling proxy; the human-in-the-loop is
your own agent harness.
Connector document indexing is the explicit bridge from external source data to
Driftless-owned retrieve substrate. Preview first; execute writes only
connector_documents. Default context retrieve stays Topics-only. Connector
retrieve is opt-in (sources:["connectors"] / include_external) and returns
trust:"external" with citations and freshness.
STOP rule: if an agent needs a broker operation that
broker operations <provider> does not list, it must report the missing
capability — never author or deploy an integration script to fill the gap.
Comments — annotate either plane
| Workflow | CLI | MCP tool | API endpoint |
|---|---|---|---|
| Comment (add / list / resolve) | context comment [add|list|resolve] | driftless_context_comment (action) | POST|GET|PATCH /comments |
open → resolved → wont_fix).
What is fast by default
The matrix encodes one rule: the interactive default never ships a heavy body.- Lists and search default to
summary(an index row) and are bounded (top 5 search, top 40 list). - Match-files and
retrievedefault tobrief— the durable why, not the fullcontent— and are bounded drifted-first (top 10). - A single
context get <slug>defaults tofull, because you named the one topic you want. fulleverywhere else is an explicit opt-in (--fullis never the default); pair it with a smalllimit.- Records (collection + broker) paginate by keyset; broker output is hard-capped.
budgets.md;
the view/pagination vocabulary in views.md; how a perf claim is
accepted in gates.md.