2026-07-06
July 6, 2026 · View on GitHub
BREAKING for tiles that provide interface instances
(provides { …: { kind: "http", "instances": true } }).
What changed
PUT /api/xbin/iface-instances now rejects workspace-absolute path
prefixes ("/api/…") with a 400. Registered prefixes are
provider-relative: xbind composes the URL it injects into consumers as
/api/<provider><prefix>.
Previously an absolute registration was accepted silently and the composed
URL doubled the prefix
(…/api/apps/imap-connector/api/apps/imap-connector/m/1), so every consumer
call 404'd — in the consumer's logs, far from the actual mistake. Trailing
/ on a prefix is now also normalized away (consumers append /sub paths).
Who's affected
Any provider that registered instances with its own /api/<self>/… prefix,
e.g.:
// BROKEN (now rejected at registration):
instances[id] = fmt.Sprintf("/api/%s/m/%d", xbin.Self(), acctID)
Consumers need no changes. Providers registering relative prefixes already were correct.
How to migrate
Register the prefix relative to your own API root:
// CORRECT:
instances[id] = fmt.Sprintf("/m/%d", acctID)
// → PUT /api/xbin/iface-instances {"instances":{"aurora":"/m/1"}}
// → consumers get url http://xbin/api/<you>/m/1
Then restart/re-register once after upgrading xbind — registration replaces the stored map, and requesters bound to you are restarted with clean URLs. Stored absolute paths from before the upgrade stay broken until you re-register (they were 404ing anyway).
Serve the instance sub-surface under your normal mux, e.g.
GET /m/{acct}/messages — an instance is a sub-surface of your API, and a
bound consumer's injected URL routes straight into it.
Why
Two reasons this is the contract (and not "inject absolute paths as-is"):
provider#instancemust only ever route into the provider — the binding grants a role on you, so an instance is structurally a sub-path of your API, never an arbitrary redirect.- Persisted registrations must not embed install paths:
/api/apps/x/…goes stale the moment the tile is renamed or cloned. Same rule as "never hardcode your own path in code" (workspaceAGENTS.md), applied to state.
The old docs showed an ambiguous example ("/api/path/prefix") in several
places, which is how absolute registrations happened in the first place —
those docs are fixed, and the validation now catches the mismatch at the
provider, where it's fixable.