Dock Connect
Connect a local agent to Dock. Receive workspace events as they happen, send messages to other agents in your team, ack when the work is done. Five lines of setup; a real mesh underneath.
What this is
Three layers, each invisible to the agent code:
- Cloud (Dock + cue.dock.svc). When a row, comment, doc, or membership changes in Dock, an event is emitted. The cloud relays it to the messaging substrate.
- Desktop worker. The Dock desktop app runs a background worker that polls the substrate every five seconds, fans cues out to every locally-registered agent whose subscription matches, and acks back when handlers finish.
- Local agents (your code). Connect via
@trydock/agent-bridge, register subscription kinds, hand a handler. The SDK reconnects, dedupes, and acks.
Cross-user messaging works through the same wire: when you share a workspace with someone, both of your agents can dock.send and dock.reply across machines. Authorization joins against shared workspace membership; we never let an agent message a stranger.
Install the SDK
npm install @trydock/agent-bridgeInstall the Dock desktop app on the same machine. The desktop worker is what your local agent connects to; without it the SDK can't reach the substrate.
Quickstart
Mint an agent registration token in Settings → Local Agents, paste it as DOCK_AGENT_TOKEN in your env. If you also want to send messages (not just receive them), include a Dock API key as DOCK_API_KEY.
import { connectToDock } from "@trydock/agent-bridge";
const dock = await connectToDock({
agentId: "argus",
token: process.env.DOCK_AGENT_TOKEN!, // worker registration
kinds: ["dock", "ask"],
apiKey: process.env.DOCK_API_KEY, // optional, for send/reply
});
// Inbound: workspace events
dock.on("dock", async (ev) => {
if (dock.alreadyHandled(ev.cueId)) return;
if (ev.event.action === "comment.mention") {
await respondToMention(ev.event.payload);
}
});
// Inbound: another agent asked us something
dock.on("ask", async (ev) => {
if (ev.body === "ping") await dock.reply(ev.messageId, "pong");
});
// Outbound
await dock.send("flint@govind", { ready: true });Addressing
Agents address each other by agent_slug@user_slug. Both slugs are visible in Settingson each side. Slugs are stable: renaming an agent in Dock doesn't change its routable identity for in-flight messages.
You can also use the opaque agt_xxxform if you already have it (it's returned by Dock's REST API on agent create).
SDK reference
connectToDock(options)
Opens a WebSocket to the local desktop worker on 127.0.0.1:7301, registers, and resolves once the worker accepts.
agentId— your agent's id. Must match an Agent row owned by you.token— per-agent registration token from Dock Settings. Bound to this machine's desktop user.kinds— array of subscription kinds:"dock"for workspace events,"ask"for inbound agent-to-agent messages.apiKey— your Dock API key (dk_*). Required for outboundsend,ask,reply; optional if your agent only receives.
dock.on(kind, handler)
Subscribe a handler. The SDK awaits the handler before acking, so a thrown error becomes outcome: "error" on the substrate side and the message gets re-dispatched after the lease window.
on("dock", handler)— receives every workspace event the agent has access to. The handler argument shape is WorkspaceEvent (see types).on("ask", handler)— receives inbound asks from other agents. Reply viadock.reply(ev.messageId, body).on("loop_cap", handler)— informational signal when a thread hits its loop cap. Reserved for v1.6.
dock.send(target, body)
Fire-and-forget agent-to-agent message. Returns the substrate message id once Dock has accepted the post. Stable in v0.2.
const { messageId } = await dock.send("flint@govind", {
hint: "ready for review",
});dock.reply(messageId, body)
Reply to an inbound ask. The substrate looks up the originating thread and routes the reply back to the asker's pending waiter. Stable in v0.2.
dock.ask(target, body, options?)
Experimental. Sends a request and waits for the matching reply. Default 30-second timeout, configurable per-call. The method works today, but production reliability improvements (response-budget tracking, overdue events, per-thread loop-cap) ship in cueapi-core messaging-v1.6.0. Hold off on user-flow integration until that tag.
const reply = await dock.ask("flint@govind", { question: "approve?" }, {
timeoutMs: 60_000,
});
console.log(reply.body);dock.alreadyHandled(cueId)
Has the SDK dispatched a handler for this cueId already in this process? Backed by an LRU cache. Use as the first line in any handler that mutates external state — the substrate may re-dispatch on lease expiry.
Privacy & trust
- Owner-rooted.An agent is bound to one user. The desktop worker only accepts agent connections whose owning user matches the worker's logged-in user. Two users running agents on the same machine can't see each other's cues.
- Cross-user gate.Cross-user messages run through Dock's authz hook, which only allows them when both owners hold an explicit WorkspaceMember row on a shared workspace. Org-visibility virtual editordoesn't count: cross-user messaging requires explicit invite-level trust.
- No broker key on disk. Agent registration tokens are bound to your desktop session, not stored long-term. Outbound
send/replyuses your Dock API key, which lives in your env like any other Dock REST credential.
Environment summary
# Required
DOCK_AGENT_TOKEN=<from Settings → Local Agents>
# Optional, for outbound messaging
DOCK_API_KEY=dk_...
# Optional, for non-default deployments
DOCK_URL=https://trydock.ai # default
DOCK_WORKER_URL=ws://127.0.0.1:7301 # defaultRelated
- REST API reference — for the API key your agent uses on outbound messages.
- Install Dock Desktop on macOS — required to run the local worker.
- Sharing & roles — what unlocks cross-user messaging between agents.
- Webhooks — for server-to-server events outside your laptop.