@kybernesis/dispatch
v0.5.0
Published
Agent-to-agent dispatch for eve agents: declared remote-peer edges with principal forwarding on by default, and a receiver channel that makes trusting the wrong caller hard to express.
Maintainers
Readme
@kybernesis/dispatch
Agent-to-agent dispatch for eve agents: declared remote-peer edges with principal forwarding on by default, and a receiver channel that makes trusting the wrong caller hard to express.
Two separately deployed eve agents talk over a declared edge. The caller
mounts a remotePeer under agent/subagents/; the receiver authors its eve
channel with dispatchChannel. Underneath is eve's native defineRemoteAgent
transport — durable park-and-resume dispatch, retried callbacks, recursive
cancellation — with the governance defaults locked in.
Caller side — one file per peer
// agent/subagents/gtm.ts (file name = tool name the model sees)
import { remotePeer } from "@kybernesis/dispatch";
export default remotePeer({
envVar: "GTM_AGENT_URL",
description:
"The company's GTM operator: posting cadence and history, open go-to-market plays, outreach targets, LinkedIn/X content drafting in the house voice.",
});The description is a routing hint, not documentation: the calling agent's
model reads it to decide when to delegate. Write the concrete topics people
actually ask about. A vague description means the edge never fires.
Defaults you'd otherwise have to remember: outbound auth is Vercel OIDC, the
URL resolves from env at runtime (no rebuild to repoint), and
forwardPrincipal: true — the peer runs as the human who asked, so its memory
scoping, per-user connections, and telemetry attribution see the real person.
Receiver side — enumerate your peers
// agent/channels/eve.ts
import { dispatchChannel } from "@kybernesis/dispatch";
export default dispatchChannel({
trustedPeers: [{ teamSlug: "acme", projectName: "acme-router" }],
});One declaration feeds both trust surfaces — the OIDC subjects allowlist
(which deployments may call at all) and the trustedForwarders predicate
(which of them may assert an end-user identity) — so the two can never drift
apart. There is deliberately no predicate form: trustedForwarders: () => true
(any authenticated caller asserts any identity, including your own preview
deployments) is not expressible through this API. Peers default to
environment: "production"; previews are never trusted implicitly.
Your own project's deployments and eve dev keep working (current-project
OIDC bypass + localDev()); production browser traffic stays rejected unless
you pass your app's real auth via extraAuth.
Bidirectional edges
Answering is built into one edge — the caller parks until the peer's terminal callback arrives, so request and response are one round trip on one wire. Add the mirror-image files only when the other agent should also be able to initiate: each direction is its own declared edge.
Operational rules
Scheduled/proactive turns have no human to forward. A turn triggered by a cron schedule carries no signed-in principal, so a dispatch made from it reaches the peer as the calling app's service identity even with
forwardPrincipal: true. Design peer-side capabilities that scheduled turns rely on to be app-scoped (static keys), not user-scoped.Upgrade both ends of an edge together. A receiver on an eve version predating principal forwarding silently drops it and runs the session as the calling app's service identity — a security downgrade with no error.
The env var (
GTM_AGENT_URLabove) holds the peer's stable production URL. Unset with nofallbackUrlfails the dispatch loudly — intended.Remote peers trace under their own deployment. Correlate hops in your observability via the
eve:forwarded-byattribute and the child session id on the caller'ssubagent.calledevent.
License
Apache-2.0
