Menu QaldyDocs

Hear when something needs you

Preview

How a connected agent learns that a run failed or an approval is waiting: ask with list_attention, subscribe where the client can, or load the Claude Code channel. What reaches the model and what never does.

When a run fails or an approval waits, you should not have to ask. There are three ways your agent can hear, for three kinds of client. They all read the same feed: the workspace's events as you may see them, only apps you can open and only approvals asked of you.

Ask: list_attention (every client)

With no arguments it says what needs attention now, such as failing apps and approvals waiting for you, and returns a cursor. With since set to that cursor it returns what happened after: runs your agent started that finished, runs that failed, approvals asked of you and alerts. waitSeconds (up to 15) holds the call open for news. The qaldy-watch prompt and the Claude Code command /qaldy:watch use it. This works in Claude on the web, ChatGPT and everything else that can call a tool.

Be told: resource subscriptions (clients that subscribe)

On the 2026-07-28 protocol the server offers one resource per person, qaldy://workspace/<workspace>/attention/<you>, and accepts a subscription to it. While a stream is open the server asks the API for your news and sends a notification when there is some. The notification carries nothing: the client then reads the resource, and the API filters it again. A subscription may name only your own resource. One token may hold three streams; the server holds at most 256. list_changed for tools is also declared, because published tools can change.

Be told in Claude Code: the channel

Claude Code accepts pushed messages from a channel: a local MCP server that declares the claude/channel capability. qaldy-mcp --channel is one. It runs over standard input and output with your token, asks the same feed, and sends each item into your session as a message. A session loads one only when started with --dangerously-load-development-channels, an organization can switch channels off, and the stdio server must use the earlier handshake (MCP_PROTOCOL_NEGOTIATION=legacy).

json
{
  "mcpServers": {
    "qaldy-events": {
      "command": "node",
      "args": ["/path/to/qaldy-cloud/apps/mcp/dist/qaldy-mcp.mjs", "--channel"],
      "env": {
        "QALDY_API_URL": "https://cloud-api.qaldy.com",
        "QALDY_TOKEN": "qat_your_token",
        "MCP_PROTOCOL_NEGOTIATION": "legacy"
      }
    }
  }
}
sh
claude --dangerously-load-development-channels server:qaldy-events

Build the file with pnpm --filter @qaldy/mcp build from a clone of the repository. The channel is not part of the plugin, because it needs that file and a token. Use a read token.

What reaches the model

A pushed message reaches a model unasked, so it holds only what a stranger could not have written: ids, enumerated codes (a run's error code, a gate status, a cap level) and the names people gave apps, with control characters, quotes and angle brackets removed. It never holds an error message, an approval title, a blocked hostname or a log line. Those stay behind inspect_run, list_approvals and the audit log, where they are marked as data. For example:

A run of "Low stock" failed with connector_rejected (run run_9). Use inspect_run to read why.

What counts as news

ItemWhen
run_finishedA run your agent started through a published tool finished
run_failedA run failed in an app you can view, yours or not
approval_neededAn approval was asked of you
alertAn app is failing, an automation is failing, a connection is not connected, a call was stopped at the gate, or the workspace reached 90 percent or more of an allowance

An alert rule firing (error rate, quiet, budget) sends its own email or Telegram message, but does not yet appear in this feed as an event; the feed carries what the rules watch. Adding it is Planned.

What it costs the audit log

A long poll would write a row for every request. A token that polls the feed gets one audit row, then at most one every ten minutes. Every call that changes something has its own row.

Type to search. Up and down to choose, Enter to open, Esc to close.