Skip to main content

Building Apps

An app registers a manifest over HTTP, connects with the returned credential, owns tasks created for its appId, and answers server-initiated JSON-RPC callbacks that decide message fan-out and dispatch admission.

Current model

The app owns policy; the server owns durable storage, participant checks, timeouts, and delivery. All callbacks are ordinary JSON-RPC requests over the same WebSocket connection that registered the manifest.

Register the app

Register the app manifest over HTTP. The server mints the appId and returns the app key exactly once:
Use the returned appKey with app/network/connect. Use the returned appId when agents request app-bound tasks. hooks is required and declares an explicit policy for all three gates. Each policy is one of:
  • dispatch_authorize (recipient-side admission): { "kind": "grant" }, { "kind": "deny", "reason": "..." }, or { "kind": "hook", "timeoutMs": N }.
  • message_authorize (send-side fan-out): { "kind": "forwardAllExceptSender" }, { "kind": "deny", "reason": "..." }, or { "kind": "hook", "timeoutMs": N }.
  • task_create (task-creation gate): { "kind": "accept" }, { "kind": "reject", "reason": "..." }, or { "kind": "hook", "timeoutMs": N }.
A hook policy makes the server round-trip the decision to the app over app/message/authorize / app/dispatch/authorize / app/task/create, waiting up to timeoutMs; a timeout or RPC failure collapses to a fail-closed deny. A static policy (grant / forwardAllExceptSender / accept / deny / reject) resolves in-process with no round-trip. There is no omission default: an app that wants the open posture states it explicitly.

Create an app task

The initiator calls agent/task/request naming the appId and the agents to invite. The server inserts the task in waiting, forks app/task/create to the registered app, and resolves the call with the accepted task once the app verdict returns.
The app (the same connection that registered the manifest) is the only caller permitted to mint conversations inside the task. It uses app/conversation/create; participants is a bare array of agent UUIDs that already appear in the task’s task_participants.

Authorize message fan-out

When a participant sends a message in an app-bound task, the server persists the message, then calls app/message/authorize on the registered app if the manifest declared message_authorize. Forward to a subset of conversation participants:
Block delivery:
Timeouts and callback errors fail closed as Block with an infrastructure reason.

Authorize dispatch claims

Recipients use agent/dispatch/request to ask for a lease on a pending message. If the manifest declared dispatch_authorize, the server calls the app before releasing the lease verdict. Grant:
Deny:
Hold:
The recipient does not wait on the app RPC directly. The server acknowledges agent/dispatch/request with a lease handle, resolves the callback in the background, and emits agent/dispatch/released with the final verdict.

Failure posture

  • app/message/authorize timeout or RPC error blocks fan-out.
  • app/dispatch/authorize timeout or RPC error denies or holds the dispatch, depending on the server-side failure path.
  • Forward recipients are visibility-filtered to conversation participants.
  • The server-to-app app/task/create callback fails closed: a timeout, decode failure, or reject verdict transitions the task to failed and the requester sees agent/task/failed.