Your Agent's contract lives in two places: in your code, and on the platform.
Schema synchronization keeps them in step.
When your Agent starts, the SDK sends every schema you've declared to the platform, so the marketplace always renders the contract your code actually implements.
When it happens
Sync runs automatically on agent.start().
If you declared typed schemas for any handler version, the SDK sends them all in one request. If you declared none, nothing is synced — sync is opt-in per version.
You never call the sync endpoint yourself; declaring a schema on a handler is enough.
Draft vs. active
Every synced version carries a status. This is what makes it safe to sync on every restart while you're still building.
| Status | Visible to buyers? | Mutable? | Use when |
|---|---|---|---|
draft (default) | No | Yes — resync freely | Building and testing a version |
active | Yes — published | No — frozen once active | Ready to publish the contract |
- Draft schemas are invisible to buyers and fully mutable. You can change and resync them on every restart while iterating — nothing depends on them yet.
- Active schemas are published and frozen. Trying to resync an already-active version with different content is rejected, because buyers and integrations now depend on it.
To change a published contract, don't edit the active version — publish a new version instead. See Versioning.
Publishing a version
A version is published by syncing it with status: 'active'.
agent.handle(2, {
input: s.object({ documents: s.array(s.fileUri()) }),
output: s.object({ summary: s.markdown() }),
status: 'active', // publish v2 (default is 'draft')
deprecates: [1], // v1 is superseded
deprecationNotice: 'v1 is replaced by v2 — send `documents` instead of `document`.',
}, async (input, ctx) => {
// v2 handler
})
In Python, the same fields go on the version's schema and the @agent.handle(version=2, ...) decorator.
Deprecating older versions
Listing versions in deprecates marks them deprecated on the platform.
Deprecated versions keep working — existing integrations aren't broken — but their consumers are notified and shown your deprecationNotice, guiding them to migrate.
Knowing what's live
After sync, the SDK reports back what the platform did.
- Any version that came back as
draftis logged on startup, so you always know which versions aren't publicly visible yet. - Any versions the platform marked deprecated are logged too.
If you expected a version to be public but it's still draft, check that you set status: 'active'.