Check the current contract and validator results before you build on this.
A document operation descriptor says what an operation means; an executable binding proves that the current runtime can perform it. Treating those as the same thing causes agents to promise unavailable work, clients to build invalid requests, and operators to mistake catalog breadth for deployed capability. A safe document API exposes both facts and checks availability again at invocation time.
What is a document operation descriptor?
A document operation descriptor is a stable, machine-readable definition of a document action: its name, purpose, input and result contracts, possible errors, possible losses and availability. A developer or agent uses it to decide whether an operation fits a request.
A descriptor is not executable code. It may exist before a particular runtime has installed the library, licensed the converter, mounted the template, enabled the feature, or connected the managed service required to execute it.
That distinction is common in infrastructure even when the terminology differs. An API description can document an endpoint that is not enabled for a tenant. A database schema can describe a function that the current role cannot call. A tool catalog can list an action whose backing integration is disconnected. Document systems need the same honesty because format support varies by engine, deployment, and policy.
What is an executable binding?
An executable binding connects one descriptor to a concrete implementation in the current environment. It answers operational questions that the descriptor alone cannot:
- Which package or service handles the operation?
- Is that implementation installed and enabled here?
- What version and policy are active?
- Which resource limits apply?
- Can this caller invoke it?
- Where will inputs and outputs be processed?
The binding should be resolved at call time. A list response captured five minutes ago can become stale after a deployment, configuration change, license change, or circuit-breaker event. The server, not the model and not the client cache, owns the final availability decision.
| Question | Descriptor answers | Binding answers |
|---|---|---|
| What does the operation do? | Yes | Inherits the descriptor |
| What input shape is valid? | Yes | Enforces that shape |
| Is it implemented in this runtime? | No | Yes |
| Is this caller authorized? | No | Yes |
| Which limits and dependencies apply now? | Declares possible fields | Resolves current values |
| Can the call execute? | No | Only after validation and authorization |
Why agents fail when the catalog overstates availability
An agent plans from the information it receives. If every described capability looks executable, the agent may select a plausible operation, construct a valid payload, and tell the user that the job is underway. The eventual failure then appears late and ambiguously: as a missing module, a generic server error, or an unexplained fallback.
That is worse than an explicit unavailable result. A typed result lets the agent explain the real boundary, ask whether an alternative is acceptable, or stop without pretending that a substitute is equivalent.
The failure is especially dangerous for document conversion. A runtime may be able to generate a DOCX but not convert it to PDF. Silently returning the DOCX, invoking a different converter, or rasterizing the pages changes the recipient artifact. Availability is therefore part of the user-visible contract, not an internal implementation detail.
Design the discovery sequence around two checks
The safe sequence is discover, describe, verify, invoke, and verify again:
list operations
-> select a descriptor
-> describe its exact contract
-> check binding availability
-> construct and validate input
-> invoke
-> resolve binding and authorization again
-> return a structured result
The first availability check improves planning. The second prevents time-of-check/time-of-use drift. The result should preserve the selected operation name, implementation identity where safe, artifact identity, diagnostics, declared losses, and an error code when execution did not occur.
For MCP servers, the protocol itself distinguishes tool discovery from tool invocation. The official MCP tools specification defines tools/list, tools/call, input schemas, optional output schemas, and separate protocol versus execution errors. An application may add progressive discovery inside that boundary, but it should not make catalog metadata look like execution authority.
Avoid three common modeling errors
Error 1: one boolean called supported
supported: true collapses too many states. Does it mean the file format is understood, the operation has a descriptor, an implementation exists somewhere, the current deployment has a binding, or the caller may execute it? Use explicit fields for descriptor stability, binding availability, authorization, and lifecycle state.
Error 2: fall back without declaring a loss
If an unavailable native chart operation falls back to an image, the runtime changed editability. If a PDF conversion path substitutes fonts, it changed appearance risk. A fallback is a new operation with a loss policy, not an invisible rescue.
Error 3: put deployment secrets in discovery metadata
Agents need enough information to plan, not private hostnames, credentials, or internal topology. Return a bounded reason such as binding_unavailable, authorization_required, or dependency_unhealthy. Keep sensitive diagnostics in operator logs.
A practical descriptor and binding shape
The exact schema is product-specific, but the responsibilities should remain separate:
{
"descriptor": {
"name": "pptx.render",
"domain": "pptx",
"verb": "render",
"inputSchemaVersion": "1",
"possibleLosses": []
},
"binding": {
"available": true,
"mode": "local",
"implementation": "@runstamp/pptx",
"reason": null
}
}
This example is illustrative. The live descriptor returned by the runtime remains authoritative. A client should never infer availability from an article, package name, or cached example.
How Runstamp applies the boundary
Runstamp’s current public truth is the stable Public GA operations across local packages, SDK, CLI, MCP, and Hosted V2. The public MCP surface uses list, describe, and invoke so an agent can narrow the catalog before loading an exact input contract. Runtime checks still enforce authorization, health, policy, and dependencies at invocation time; the separately GA Platform control plane provides self-serve environments, keys, durable jobs, review, approval, release, delivery, audit, usage, billing, webhooks, notifications, and dashboard controls.
Use the operation catalog to understand the result boundary, the agent guide for progressive discovery and recovery, and the evidence index for what an artifact result can and cannot prove.
Test descriptor and binding behavior separately
A descriptor test should prove that the public contract is stable and complete. Load the catalog in a clean process, assert that operation names are unique, validate every input and result schema, and confirm that every documented error and loss code has a definition. Snapshot tests are useful because an accidental rename or schema contraction should require an explicit compatibility decision. They should not claim that a converter, credential, or hosted worker is currently available.
A binding test asks different questions. Start the actual runtime with a known configuration and check the resolved implementation name, version, mode, limits, and health. Include a negative control with the implementation removed or disabled. The runtime should keep the descriptor discoverable when that helps planning, but mark the binding unavailable and reject invocation with the documented code. This proves that availability is measured rather than inferred from catalog data.
Also test stale discovery. Fetch an available binding, disable it, and then invoke with the earlier descriptor. The server must resolve authorization and availability again. A cached available: true field is planning information; it is never permission to bypass the current runtime decision.
For multi-tenant systems, run the same test with two principals. They may receive the same descriptor while resolving different authorization, quota, data-region, or destination bindings. Keep those tenant-specific facts out of the stable descriptor unless they are intentionally part of its public schema.
The resulting evidence should contain two independent records: a catalog contract result and a runtime binding result. This separation makes failures actionable. Descriptor drift points to versioning or documentation. Binding failure points to deployment, configuration, authorization, health, or policy. Combining them into one green capability flag removes that diagnostic value.
Decision checklist
Before exposing document operations to an application or agent, verify that:
- descriptors and bindings have different types and lifecycle states;
- discovery reports current availability without leaking private topology;
- invocation resolves the binding and authorization again;
- unavailable operations return typed, non-retryable explanations;
- fallbacks require an explicit loss policy;
- logs distinguish selection, validation, binding, and execution failures;
- public capability counts do not mix described and executable operations.
The core rule is simple: describe broadly if it helps planning, but execute only what the current runtime can prove it has bound.
Keep the document workflow in your product.
Pick an operation, run it on a real file, then embed review and release where your customers work.