Routes
A route is a file under routes/<path>.ts that exports named HTTP-method functions. There is no registration step. The assistant resolves each request against the plugin routes/ directory at request time.
Where routes are served
/x/plugins/<plugin-name>/<path>
That prefix resolves only against <workspace>/plugins/<name>/routes/. It never falls back to a workspace routes/plugins/… file. A missing file is 404. A disabled plugin serves no routes. Standalone workspace routes live at /x/<path> from <workspace>/routes/.
Path mapping
| File | Served at |
|---|---|
routes/status.ts | /x/plugins/<name>/status |
routes/webhooks/incoming.ts | /x/plugins/<name>/webhooks/incoming |
routes/index.ts | /x/plugins/<name> |
.js wins over .ts. A direct file wins over an index file for the same path.
Writing a handler
export async function GET(request: Request): Promise<Response> {
return Response.json({ ok: true });
}
export async function POST(request: Request, context): Promise<Response> {
const { conversationId, text } = await request.json();
await context.conversations.postMessage(conversationId, text);
return Response.json({ delivered: true });
}
Supported methods: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS. An unsupported method returns 405 with an Allow header. Handlers may also import from @aevumcadence/plugin-api.
Loading and lifecycle
Loaded lazily on the first matching request and cached by path plus mtime. Edit the file and the next request picks it up. A throw is 500. Longer than 30s is 504.
Calling from an app
Use window.cadence.fetch("/x/plugins/my-plugin/status"). Never the global fetch. The wrapper prepends the /v1 API prefix. External webhooks use plain HTTP. See Apps.
When to write a route
When something outside the assistant needs to reach in over HTTP: a webhook, an OAuth callback, a status endpoint. If the model should invoke the action, write a tool.