Find a realm by its name, not its address
The named-services discovery service is the registry that lets a consumer find and reach a namespace published by another app — by namespace, not by hardcoded address. An owner app publishes its complete current provider registry; consumers resolve an eligible provider for each request, across app packages.
An app explicitly publishes a provider for a namespace —
task, mem, cnv, parts. An agent in a
different app wants to use it. The two were built separately, deployed separately,
and neither knows where the other runs. The thing that connects them is the
named-services discovery service: a small registry where a consumer asks
"which published provider can answer this task request?" and gets
back an answer — without anyone hardcoding an address.
That one move — resolve by namespace, not by location — is what makes the ecosystem composable. (For the full realm-connection picture, see the Deep blog "Your app as a service provider in the agentic network"; this Short is only about the find.)
The registry: a directory of published providers
The discovery service is a small directory of explicitly published providers, scoped to one tenant and project. Its core is an index keyed by namespace: each namespace name points to the set of providers that publish it. Normally one dedicated app owns a realm. Multiple providers may share a namespace only when the partition is intentional and the request can select among them by operation, ref, or object kind.
discovery table (per tenant / project)
namespace:parts → { inventory.parts }
namespace:task → { task.issue }
namespace:mem → { sdk.memory }
Nothing here is an address. The index maps a name to who — the where is carried separately, in each provider's record, and only handed to a caller once discovery has resolved the name.
How providers publish: reconcile on load
A provider decorator describes a contract; it does not publish that provider. The owner
app explicitly contributes the provider to its current registry. On load, the app reconciles
that complete registry with discovery. Each provider record says what it
serves — its namespaces, operations, refs, object kinds, and
provider_id — and how to reach it — the
endpoint: the transport, the app package it lives in, and the provider handle.
provider record
namespaces: parts
provider_id: inventory.parts
endpoint: transport · app package · provider
Current provider records are upserted and indexed under every namespace they serve. Records that the same app published before but omitted from its current registry are withdrawn; publishing an empty registry withdraws all of that app's old providers. Another app's records are untouched. This prevents a reusable mixin or an old deployment from becoming an accidental second owner.
How consumers discover: resolve by namespace
A consumer app does not hardcode a provider location. In config it
declares that it consumes namespace parts. At call time discovery reads the
namespace:parts candidates, selects a provider that supports the request, and
returns its endpoint — even though that provider lives in a
different app package.
consumer: "I consume namespace `parts`"
│
▼
discovery.resolve(namespace="parts", operation="object.search")
│ read namespace:parts → eligible inventory.parts → its record
▼
endpoint → transport · the publishing app package · provider
│
▼
the agent calls the generic named-service operation on the realm
it never had to locate
The consumer never learned an address, a host, or which app package owns parts. It
learned a name, and discovery did the rest. Move the provider to a different
app, re-deploy it, let the owner publish its current registry — the consumer config doesn't
change, because it was never pointing at a place.
Why this is the composable seam
Hardcoding a provider's location couples two apps forever: you cannot move, split, or replace the provider without editing every consumer. Discovery breaks that coupling. An owner app publishes its current state; consumers resolve the current provider at request time — same tenant and project, across app packages.
Discovery is routing, not exposure. A REST, MCP, Data Bus, or local adapter still defines how the call crosses the boundary, and that surface still applies its own authentication and authorization. Discovery only removes the hardcoded location.
Since then: the record grew a second reader
The published spec's metadata now also carries the realm's HUMAN layer —
presentation (purpose, works-with, human labels per operation/action), object-kind
one-liners, and connected-account requirements for provider-backed realms. The capability
picker resolves the very same discovery record and renders it as the realm's service card:
one provider spec, two readers.
And a realm's agent consumers now enter per agent: whether the caller is an external
MCP client or an agent hosted in a KDCube app, it acts under the user's delegated-by grant
for that specific agent, checked at the attempt — with the raw claim tokens
(mail:read, slack:post) as the consent language everywhere the
user reads or grants them. The provider does not implement that delegation gate; the
boundary is the platform's.
Documentation on GitHub
The live docs behind this entry: