Capability descriptors
A descriptor is the interface a caller discovers: an exact id and semantic version, a useful description, JSON Schemas, and an I/O mode. Its content revision binds discovery to invocation.
Choose the I/O contract
| Mode | Initial request | Caller chunks | Provider chunks | Final result |
|---|---|---|---|---|
unary | input_schema | — | — | output_schema |
server_streaming | input_schema | — | output_chunk_schema | Optional output_schema |
client_streaming | input_schema | input_chunk_schema | — | Optional output_schema |
bidirectional | input_schema | input_chunk_schema | output_chunk_schema | Optional output_schema |
Declare chunk schemas precisely for directions that exist; other modes forbid them. Use additionalProperties: false when the contract should reject unknown fields. Descriptions should explain units, formats, limits and failure conditions to both people and generative callers.
from skulk.extensions import CapabilityDescriptor
ECHO_DESCRIPTOR = CapabilityDescriptor(
id="echo", version="1.0.0", title="Echo",
description="Return the supplied text unchanged.",
io_mode="unary",
input_schema={
"type": "object",
"properties": {"text": {"type": "string"}},
"required": ["text"], "additionalProperties": False,
},
output_schema={
"type": "object",
"properties": {"text": {"type": "string"}},
"required": ["text"], "additionalProperties": False,
},
)
Managed children use the SDK's equivalent Descriptor. Keep provider identity, transport-node identity, and descriptor identity separate.
Discover, then pin
- Find a candidate provider through the cluster's capability tags.
- Describe that node using
context.describe_node(node_id)orGET /v1/capabilities?node_id=.... - Select the exact
id@versionand retain its descriptor revision. - Send that revision with the call. A changed contract returns
revision_mismatch; rediscover before deciding whether to retry.
The HTTP response maps every id@version to its revision in revisions. Do not invent a digest, assume that a name has only one version, or treat a cached descriptor as proof of current admission capacity. A revision does not grant permission.
Evolve the interface
A breaking behavior or shape change needs a new semantic version. Any descriptor-content change also changes its revision, even when the semantic version remains unchanged. Existing callers must negotiate again. Input and output validation never fetch remote schema references.
Explore example or live descriptors · Calling and streaming · Normative provider contract