KDCube
← Engineering

Every tool an agent carries costs something before it is ever called.

It occupies context. It competes for the agent's attention at every decision. It ships its own parameter shapes, its own error dialect, its own half-documented conventions. Connect an agent to mail, chat, conversation history, boards, and memory the direct way — one tool per operation — and the tool list grows with every domain. Twenty domains later the agent spends its judgement choosing between eighty near-synonyms, and every new domain makes every old one slightly harder to use.

Named services take the other road. The agent carries a bounded grammar of generic operations, and each domain plugs in as a realm — a namespace that describes itself: what its objects are, how to find them, what can be done to them, and who may do it. The grammar is learned once. The domains are open-ended.

TWO WAYS TO CONNECT DOMAINS TO AN AGENT one tool per operation every domain ships its own verbs into the context agent search_gmail read_gmail_message send_gmail download_attachments forward_gmail search_slack list_channels read_history post_message upload_file memory_search memory_save canvas_patch tool count grows with every domain one grammar, self-describing domains generic operations; each realm teaches its own vocabulary agent THE AGENT GRAMMAR · BOUNDED about schema list search get action upsert host_file delete THE REALMS · OPEN-ENDED mail: slack: conv: mem: cnv: more… tool count stays bounded; domains scale
Two ways to connect domains. The agent grammar is bounded; the realms are open-ended.

Implementation highlights

The shipped system is not only a naming convention. These contracts make the small grammar work across apps, processes, agents, and UI surfaces:

ConceptImplemented contract
Bounded agent grammarThe model-callable SDK surface has at most nine generic tools: provider_about, object_schema, list_objects, search_objects, get_object, object_action, upsert_object, host_file, and delete_object. A tool appears only when at least one configured namespace allows its provider operation.
Provider-owned ontology and affordancesThe provider owns object kinds, canonical refs, relations, constraints, selectors, bounded actions, and human presentation. Semantic object search appears only when the provider supplies it; KDCube does not index the provider's object space. Its adapter translates domain requests into provider IDs and API calls.
Recursive capability discoveryobject_schema returns a root catalog, one nested schema_path, ranked capability matches for query, one kind, or one exact operation contract. The shared capability index contains provider declarations only and reports whether lexical, semantic, or hybrid matching actually ran.
Cross-process discoveryProviders register per tenant/project in Named Service Discovery. Consumers resolve a provider by namespace, operation, ref pattern, and object kind instead of linking to its app code.
Opaque, round-trippable refsGeneric clients preserve object_ref and ask the owner to resolve it. A ref carries owner/object identity without ambient object-selection state; caller identity and delegated authority travel separately in the authorization context.
One contract, several adaptersAgent tools, the external MCP gateway, canvas/chat resolvers, react.pull, jobs, and peer apps adapt to the same provider operations. They share semantics without pretending every surface is a model tool.
Actor and grantor stay distinctAn agent, external connector, or automation is a delegated actor, not the user. The approving user remains the grantor; the actor identity, delegated resources/operations, expiry, and revocation state remain independently auditable.
Layered authorizationConsumer allow-lists, per-user capability choices, and the caller's delegated grants guard the outer boundary; provider ACLs or connected-account claims guard the realm itself.
Actionable consentConnected-account requirements can be presented proactively. If an attempted operation still lacks access, one structured error names the reason, claims, account candidates, openable Connection Hub route, and retry behavior.
Complete data without context floodingSearch emits lean object refs. Long collections expose cursors; large objects and files expose signed out-of-band delivery or a harness stream. The client decides how much retrieved data enters model context.

The practical lesson is that genericity comes from a strict ownership boundary: the platform owns the grammar and routing; each realm owns meaning, identity, authorization, and effects.

The whole idea in one line

The platform fixes the verbs; each domain declares its nouns and use cases; policy and grants decide who may conjugate what.

the tools   provider_about · object_schema · list_objects · search_objects
            get_object · object_action · upsert_object
            host_file · delete_object                       (bounded at nine)
the nouns   object kinds + refs, declared per realm          (open-ended)
the guard   consumer policy and grants at the boundary,
            the realm's own authorization inside             (layered)

This is why ontology-guided fits. A realm publishes a lightweight operational ontology — the domain's entities, identities, relations, and constraints. The selectors, bounded operations, claims, errors, and delivery choices are its affordance layer: the executable language over that model. This is not a claim of formal OWL/RDF ontology or automated logical inference.

The schema is the realm's language for an agent, not a catalog of the provider's endpoints. It can say that documents contain tabs, comment threads, replies, and exports; it can offer selectors such as a tab title or a comment topic. The provider adapter turns a supported domain request into opaque provider IDs and one or more API calls. The schema advertises only what that adapter can execute: ambiguity returns choices, and unavailable or preview-only behavior is reported precisely.

Those are the generic agent-facing tool names. The provider protocol also contains operations used by adapters — for example provider.capabilities, object.resolve, and block production/rendering. An MCP gateway may expose discovery wrappers around them, while a UI may call a resolver. They do not inflate the agent's tool catalog into domain-specific tools.

A hundred APIs become a navigable realm, not a hundred tools

There are two reductions, and they happen in different places.

First, the provider adapter maps implementation endpoints into user-meaningful objects and effects. Several API calls may implement one action. Distinct effects that need separate authorization remain distinct actions.

Second, the provider arranges those declared operations in a recursive capability catalog. A catalog can be as deep as the domain needs:

docs /
  documents
  work /
    read
    edit
    transfer
  discussion

The agent can browse one node with object_schema(schema_path="/work/edit") or ask the schema itself:

object_schema(query="reply to a comment", search_mode="hybrid")
  -> catalog_path: /discussion
  -> object_kind: docs.comment_thread
  -> schema_operation: object.action:reply_comment

It then expands that exact kind/operation pair and receives one executable payload contract. If a provider really has 100 distinct agent effects, it still declares 100 stable operation ids. They no longer arrive as 100 top-level tools or 100 full schemas in every round.

The query above searches capability declarations: labels, descriptions, keywords, kinds, and operation ids. It does not search the user's documents, mail, or messages. search_objects(query=...) remains the separate provider-backed object search.

ONE SCHEMA CALL · TWO WAYS TO FIND THE NEXT CONTRACT FIXED AGENT GRAMMAR object_schema one generic tool BROWSE · RECURSIVE CATALOG / docs realm documents /documents work /work discussion /discussion read edit transfer Each node returns child summaries and direct operations. SEARCH · CAPABILITY INDEX object_schema(query= "reply to a comment") MATCH path /discussion kind docs.comment_thread op object.action:reply_comment expand one exact contract INDEX BOUNDARY catalog labels · descriptions · keywords · kinds · operation ids provider objects stay in the provider realm
Browse the realm or ask what it can do; expand one exact contract before acting.

What a realm declares

Modeling a domain as a realm means answering six questions. The mail: realm answers them like this:

ANATOMY OF ONE REALM — WHAT A DOMAIN DECLARES (EXAMPLE: mail:) object kinds the domain's nounsmail.account · mail.message · mail.attachment typed objects refs mail:gmail:<account>:message:<id> — resolves later, with no ambient selection state round-trip search + selectors domain questions + natural object selection — account · author · status · title resolvable actions named use cases with explicit policy — send · forward · request_upload policy-guarded complete data compact results continue through next_cursor · signed URL · stream reachable about · schema objects · selectors · actions · claims — provider dialect stays behind the adapter self-teaching A realm owns meaning; its adapter owns provider translation.
A realm owns meaning; its adapter owns provider translation.
  • Object kinds are the domain's nouns — typed, with the fields an operator can actually act on. Internal ranking scores and storage details stay out of the model.
  • Refs are the identities. A ref emitted by search or list is a promise: hand it back to get or action later — from another process, another session, another client — and it resolves. Refs embed what they need (mail:gmail:<account>:message:<id> carries its account), so no ambient object-selection state is required. Authorization context still travels separately.
  • Search and selectors speak the domain's own question language and natural ways to identify an intended object. Mail can select by account and query; memory by origin, kind, and labels; a document realm by title, author, or status. The provider resolves those terms to opaque IDs and returns choices when a request is ambiguous.
  • Actions are the domain's use cases, named and bounded: send, forward, post_message, request_upload. Each action is a deliberate decision about what this domain offers to outside operators. Dispatch uses object.action, while policy may grant an exact key such as object.action.send independently.
  • Complete data stays reachable through pagination cursors, signed out-of-band delivery, and harness streams even when the ordinary result stays compact.
  • About and schema make the realm self-teaching. They describe its recursive capability catalog, objects, selectors, actions, claims, account selection, file delivery, and consent errors. Provider endpoint names and call sequences stay behind the adapter.

Same verb, every domain's vocabulary

Once the grammar is fixed, domains stop being integrations and start being vocabularies. The operator's skill transfers completely: learn to work one realm, and the next realm costs only a schema read.

ONE GRAMMAR × MANY REALMS — SAME VERB, EACH DOMAIN'S OWN VOCABULARY mail: slack: mem: cnv: search receipts from a vendor, across labeled accounts decisions in a channel, messages or files durable notes by meaning, labels, kind, and origin pinned cards about a topic get a message with body and attachment refs channel history, a file by its ref one memory record, text, context, revision a board with cards, comments, provenance act send · forward request_upload post_message upload_file upsert · confirm retire · delete upsert = patch comment · move
The grammar is the interface; the vocabulary is the domain's.

A real trace, end to end, from an external agent connected over MCP — finding the pictures a teammate posted with a phrase:

search  namespace=slack  query="ПР 176 in:#kdcube-users"
   -> one hit: slack:…:message:C…:1782589383.978809   (labeled account, channel, ts)
get     the channel ref, window = that one timestamp
   -> the message object: text + THREE file refs (slack:…:file:F…)
get     each file ref
   -> download: {encoding: "url", url, expires_at}    (signed, short-lived)
HTTP GET each url
   -> three PNGs, bytes never inside a tool result

There is no Slack-specific tool schema on the agent's side: one generic search, one generic channel read, then one generic file read per returned ref. The same operations, with different provider-declared vocabulary, walk mail, memory, boards, and conversation history.

The signed URL is a KDCube delivery boundary, not a provider token. For a KDCube-hosted artifact it streams stored bytes. For a connected Mail, Slack, or Google Sheets object it can verify the signed ref, resolve the user's current credential and consent server-side, and stream current provider data. A resident harness agent instead materializes a stable turn snapshot. The caller grant is checked when the URL is minted; the URL itself is the short-lived download capability, while provider consent is checked again on each use. In every case complete data remains reachable while the model-facing result stays compact.

Two authorization gates

Exposing a domain to outside operators is an act of trust. The runtime applies two gates that answer two different questions.

LAYERED AUTHORIZATION · TWO GATES operator agent or app gate 1 · the door consumer policy + grants checked per resource / operation mail:read mail:send slack:read slack:write caller + delegation allowed? actor grantor gate 2 · the realm actor + projected authority meet the domain's own rules gmail:send chat:write realm's own ACLs may this actor do this, here, now? the domain objects · use cases a denial is an answer: reason · candidates · where to fix it · retry hint
Grants at the door, the realm's own rules inside — and a denial is an answer, never a dead end.

Identity rule: agent is not user. A hosted agent, an external MCP client such as Claude Code, and an automation using a manually issued token are separate delegated actors. The user who approved access remains the grantor. That is one delegated-representative identity model: hosted-agent linkage is automatic, while a connector or manually issued token is linked through Connection Hub. The distinction enables per-agent consent, revocation, audit, and accounting without handing an agent the user's full session.

Gate one belongs to the consumer/platform boundary. App configuration exposes only allowed namespace operations; per-user capabilities and, for external MCP or automation clients, consented delegated grants narrow that surface further, down to exact variants such as object.action.send when declared. The question is: may this caller, under this delegation, invoke this operation on this resource?

Gate two belongs to the domain. The realm receives the delegate actor plus the authority projected from the grantor and authorizes with its own rules — connected-account claims for provider-backed realms (gmail:send, slack:files:write), the realm's ownership/ACL model everywhere else. The agent is never silently rewritten into the user.

Connected-account requirements can be declared in provider metadata and shown proactively in the capability picker. The attempted operation remains the authoritative, demand-driven check: if a required claim or account is still missing, that exact attempt raises a scoped ask. A denial is an answer, never a dead end:

needs_connected_account_consent
  reason:              connect_required | claim_upgrade_required |
                       reconnect_required | account_required
  candidates:          [{account_id, label, email, workspace, status, claims}]
  connection_hub_url:  openable deep link (absolute for external clients)
  retry_hint:          whether retrying after the stated fix should succeed
  instructions:        the agent's next step, in words it can relay

An operator that hits a wall learns which wall, who can open it, and whether to retry. The agent relays a fix; the user performs one consent; the call succeeds.

Model your own domain

The recipe generalizes to any subsystem you want operators to work with. Take a logistics desk as an example — shipments, carriers, exceptions:

  1. Name the nouns. freight.shipment, freight.carrier, freight.exception — the entities an operator reasons about, with the fields they can act on.
  2. Give them identities. freight:shipment:<id>, freight:exception:<shipment>:<seq> — refs that round-trip with no ambient object-selection state; authorization travels separately.
  3. Write the questions and selectors. Search filters the desk already thinks in — status, carrier, route, overdue_days — plus how an operator names one intended shipment or exception.
  4. Name the use cases. reschedule, assign_carrier, escalate_exception, attach_pod — the operations the domain chooses to offer, each a bounded verb with a declared payload.
  5. Guard them. freight:read for search/get; freight:dispatch for the actions that move real trucks. The door checks grants; the domain applies its own approval rules inside.
  6. Arrange the capability catalog. Group operations by domain and subdomain; add labels, descriptions, and keywords that make paths and capability queries useful.
  7. Teach it. Put selection and ambiguity rules, the file story, capability limits, and denial shapes into about/schema; keep provider API details behind the adapter.
  8. Keep data reachable. Declare cursors, complete signed delivery, and harness stream behavior.
  9. Teach it to humans too. Declare the presentation layer beside the schema: a purpose sentence, an honest works-with line, human labels per operation and action ("Reschedule a shipment"), object-kind one-liners. The capability picker renders exactly this as the realm's service card — the user reads it, understands it, and narrows it per operation.

The test of a good realm now has two readers: an operator who has never seen your domain opens the schema root, browses or searches capabilities, expands one exact operation, finds an object, and performs one guarded action correctly without learning provider IDs; and a user who has never seen your domain reads its card and knows what it does, what it touches, and how to turn any part of it off.

One realm contract, every operator

The same declaration serves every kind of operator the platform hosts:

  • Any agent can receive the generic named-service tools in its catalog and reach configured realms inside its run — searching conversations, reading memory, sending mail, or patching a board.
  • External agents over MCP connect to one gateway surface, consent to grants, and work the same realms with the same verbs — including moving real files through signed upload slots and download URLs.
  • UIs keep refs opaque and call resolver adapters for capabilities, preview, open, download, or owner-defined actions. Named-service search results remain object artifacts, not files.
  • Automations and peer apps address the same objects through an explicit authorization context and the provider/client contract, without requiring a browser session.

That is the payoff of modeling the domain once through an ontology-guided contract: the vocabulary is written one time, by the people who own the domain — and every operator, human-driven or agentic, inherits it.

KDCube Deep · 06.07.2026