@cursor/july 0.1.27 → 0.1.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/dist/bin/agent-serve.js +12 -3
  2. package/dist/channels/slack/auth.d.ts +13 -13
  3. package/dist/channels/slack/auth.d.ts.map +1 -1
  4. package/dist/channels/slack/auth.js +19 -10
  5. package/dist/channels/slack/cursor-account.d.ts.map +1 -1
  6. package/dist/channels/slack/cursor-account.js +3 -1
  7. package/dist/channels/slack/defaults.d.ts +7 -4
  8. package/dist/channels/slack/defaults.d.ts.map +1 -1
  9. package/dist/channels/slack/defaults.js +14 -4
  10. package/dist/channels/slack/dispatch.d.ts +6 -0
  11. package/dist/channels/slack/dispatch.d.ts.map +1 -1
  12. package/dist/channels/slack/dispatch.js +59 -21
  13. package/dist/channels/slack/external-policy.d.ts +27 -0
  14. package/dist/channels/slack/external-policy.d.ts.map +1 -0
  15. package/dist/channels/slack/external-policy.js +53 -0
  16. package/dist/channels/slack/index.d.ts +1 -0
  17. package/dist/channels/slack/index.d.ts.map +1 -1
  18. package/dist/channels/slack/index.js +1 -0
  19. package/dist/channels/slack/interactive.d.ts +6 -0
  20. package/dist/channels/slack/interactive.d.ts.map +1 -1
  21. package/dist/channels/slack/interactive.js +42 -15
  22. package/dist/channels/slack/slack-channel.d.ts.map +1 -1
  23. package/dist/channels/slack/slack-channel.js +19 -6
  24. package/dist/channels/slack/types.d.ts +10 -0
  25. package/dist/channels/slack/types.d.ts.map +1 -1
  26. package/dist/docs/404.html +2 -2
  27. package/dist/docs/ab.html +3 -3
  28. package/dist/docs/assets/{app.BICLoJYF.js → app.CqjrYaT2.js} +1 -1
  29. package/dist/docs/assets/chunks/@localSearchIndexroot.VWQoPFJ1.js +1 -0
  30. package/dist/docs/assets/chunks/{VPLocalSearchBox.wN4Ko9dT.js → VPLocalSearchBox.ag-MwUel.js} +1 -1
  31. package/dist/docs/assets/chunks/{theme.dnnTE-Co.js → theme.BS-DJWat.js} +2 -2
  32. package/dist/docs/assets/{guides_slack.md.D_xFKlnF.js → guides_slack.md.CjmJSvZS.js} +8 -4
  33. package/dist/docs/assets/guides_slack.md.CjmJSvZS.lean.js +1 -0
  34. package/dist/docs/assets/guides_webhooks.md.wSOYas3X.js +183 -0
  35. package/dist/docs/assets/{guides_webhooks.md.B1EswtUu.lean.js → guides_webhooks.md.wSOYas3X.lean.js} +1 -1
  36. package/dist/docs/assets/{index.md.Dfv5ic9t.js → index.md.CH_s5uZe.js} +1 -1
  37. package/dist/docs/assets/{reference_channels.md.DdmiKgqf.js → reference_channels.md.CDhTRfUz.js} +2 -2
  38. package/dist/docs/assets/{reference_channels.md.DdmiKgqf.lean.js → reference_channels.md.CDhTRfUz.lean.js} +1 -1
  39. package/dist/docs/building-with-agents.html +3 -3
  40. package/dist/docs/concepts.html +3 -3
  41. package/dist/docs/deployment.html +3 -3
  42. package/dist/docs/evals.html +3 -3
  43. package/dist/docs/example-agents/approval-buddy.html +3 -3
  44. package/dist/docs/example-agents/benny.html +3 -3
  45. package/dist/docs/example-agents/bugbot.html +3 -3
  46. package/dist/docs/example-agents/codebase-wiki.html +3 -3
  47. package/dist/docs/example-agents/codeowners-review.html +3 -3
  48. package/dist/docs/example-agents/concierge.html +3 -3
  49. package/dist/docs/example-agents/fsd.html +3 -3
  50. package/dist/docs/example-agents/index.html +3 -3
  51. package/dist/docs/example-agents/knowledge-base.html +3 -3
  52. package/dist/docs/example-agents/oncall.html +3 -3
  53. package/dist/docs/example-agents/security-reviewer.html +3 -3
  54. package/dist/docs/example-agents/slack-agent.html +3 -3
  55. package/dist/docs/example-agents/weather-agent.html +3 -3
  56. package/dist/docs/guides/agent-to-agent.html +3 -3
  57. package/dist/docs/guides/cloud-runtime.html +3 -3
  58. package/dist/docs/guides/github.html +3 -3
  59. package/dist/docs/guides/human-in-the-loop.html +3 -3
  60. package/dist/docs/guides/mcp-oauth.html +3 -3
  61. package/dist/docs/guides/slack.html +11 -7
  62. package/dist/docs/guides/webhooks.html +138 -5
  63. package/dist/docs/hashmap.json +1 -1
  64. package/dist/docs/hillclimbing.html +3 -3
  65. package/dist/docs/index.html +5 -5
  66. package/dist/docs/quickstart.html +3 -3
  67. package/dist/docs/reference/agent-config.html +3 -3
  68. package/dist/docs/reference/channels.html +5 -5
  69. package/dist/docs/reference/cli.html +3 -3
  70. package/dist/docs/reference/connections.html +3 -3
  71. package/dist/docs/reference/hooks.html +3 -3
  72. package/dist/docs/reference/http-api.html +3 -3
  73. package/dist/docs/reference/instructions.html +3 -3
  74. package/dist/docs/reference/playground.html +3 -3
  75. package/dist/docs/reference/project-layout.html +3 -3
  76. package/dist/docs/reference/prompt.html +3 -3
  77. package/dist/docs/reference/schedules.html +3 -3
  78. package/dist/docs/reference/sessions.html +3 -3
  79. package/dist/docs/reference/skills.html +3 -3
  80. package/dist/docs/reference/subagents.html +3 -3
  81. package/dist/docs/reference/tools.html +3 -3
  82. package/dist/docs/scaffolding-agents.html +3 -3
  83. package/dist/docs/storage.html +3 -3
  84. package/dist/docs/troubleshooting.html +3 -3
  85. package/dist/internal/cli-ax.d.ts +8 -0
  86. package/dist/internal/cli-ax.d.ts.map +1 -1
  87. package/dist/internal/cli-ax.js +116 -57
  88. package/dist/internal/cursor-slack-relay.d.ts +2 -0
  89. package/dist/internal/cursor-slack-relay.d.ts.map +1 -1
  90. package/dist/internal/cursor-slack-relay.js +1 -0
  91. package/dist/internal/deploy-client.d.ts +2 -0
  92. package/dist/internal/deploy-client.d.ts.map +1 -1
  93. package/dist/internal/deploy-client.js +1 -0
  94. package/dist/internal/discovery.js +8 -1
  95. package/dist/internal/server.js +10 -5
  96. package/dist/playground/assets/{index-BDCeW4uc.js → index-CkN74U_L.js} +48 -47
  97. package/dist/playground/index.html +1 -1
  98. package/docs/README.md +1 -0
  99. package/docs/guides/slack.md +32 -7
  100. package/docs/guides/webhooks.md +183 -0
  101. package/docs/reference/channels.md +2 -1
  102. package/package.json +1 -1
  103. package/skills/setup-slack/SKILL.md +3 -0
  104. package/src/bin/agent-serve.ts +12 -3
  105. package/src/channels/slack/auth.ts +29 -22
  106. package/src/channels/slack/cursor-account.ts +2 -0
  107. package/src/channels/slack/defaults.ts +24 -4
  108. package/src/channels/slack/dispatch.ts +42 -1
  109. package/src/channels/slack/external-policy.ts +62 -0
  110. package/src/channels/slack/index.ts +1 -0
  111. package/src/channels/slack/interactive.ts +42 -10
  112. package/src/channels/slack/slack-channel.ts +20 -3
  113. package/src/channels/slack/types.ts +12 -0
  114. package/src/internal/cli-ax.ts +110 -34
  115. package/src/internal/cursor-slack-relay.ts +3 -0
  116. package/src/internal/deploy-client.ts +3 -0
  117. package/src/internal/discovery.ts +8 -1
  118. package/src/internal/server.ts +9 -5
  119. package/dist/docs/assets/chunks/@localSearchIndexroot.CQJytDwU.js +0 -1
  120. package/dist/docs/assets/guides_slack.md.D_xFKlnF.lean.js +0 -1
  121. package/dist/docs/assets/guides_webhooks.md.B1EswtUu.js +0 -50
  122. /package/dist/docs/assets/{index.md.Dfv5ic9t.lean.js → index.md.CH_s5uZe.lean.js} +0 -0
@@ -1 +0,0 @@
1
- import{_ as a,c as e,o as i,ag as t}from"./chunks/framework.CAZyNGu9.js";const c=JSON.parse('{"title":"Slack","description":"Put the agent in Slack over Socket Mode: manifests, tokens, doctor, engagement rules, and approval buttons.","frontmatter":{"title":"Slack","description":"Put the agent in Slack over Socket Mode: manifests, tokens, doctor, engagement rules, and approval buttons."},"headers":[],"relativePath":"guides/slack.md","filePath":"guides/slack.md"}'),n={name:"guides/slack.md"};function h(l,s,o,p,r,d){return i(),e("div",null,[...s[0]||(s[0]=[t("",54)])])}const g=a(n,[["render",h]]);export{c as __pageData,g as default};
@@ -1,50 +0,0 @@
1
- import{_ as i,c as a,o as e,ag as n}from"./chunks/framework.CAZyNGu9.js";const c=JSON.parse('{"title":"Webhooks & custom channels","description":"Give the agent its own HTTP surface: validated routes, sessions keyed to your domain, and replies delivered back out.","frontmatter":{"title":"Webhooks & custom channels","description":"Give the agent its own HTTP surface: validated routes, sessions keyed to your domain, and replies delivered back out."},"headers":[],"relativePath":"guides/webhooks.md","filePath":"guides/webhooks.md"}'),t={name:"guides/webhooks.md"};function h(l,s,p,d,k,r){return e(),a("div",null,[...s[0]||(s[0]=[n(`<h1 id="webhooks-and-custom-channels" tabindex="-1">Webhooks and custom channels <a class="header-anchor" href="#webhooks-and-custom-channels" aria-label="Permalink to &quot;Webhooks and custom channels&quot;">​</a></h1><p>A custom channel gives the agent its own HTTP surface. You get routes with validated payloads, sessions keyed to something in your domain (a thread, a ticket, a PR), and replies delivered back to the caller. The <a href="./slack.html">Slack</a> and <a href="./github.html">GitHub</a> packs build on this mechanism. This page is the mechanism itself.</p><h2 id="what-you-already-have" tabindex="-1">What you already have <a class="header-anchor" href="#what-you-already-have" aria-label="Permalink to &quot;What you already have&quot;">​</a></h2><p>The built-in HTTP channel is always mounted (under <code>/&lt;slug&gt;</code> in the default multi-agent layout). <code>POST /v1/session</code> starts a conversation, <code>POST /v1/session/:id</code> follows up, and <code>GET /v1/session/:id/stream</code> streams NDJSON events, plus sessions, approvals, and tool routes. The full list is in the <a href="./../reference/http-api.html">HTTP API reference</a>.</p><p>Write a custom channel when that shape doesn&#39;t fit: a webhook with its own payload contract, a surface that keys sessions by a domain id, or a flow that does host-side work before (or instead of) a model turn.</p><h2 id="define-a-channel" tabindex="-1">Define a channel <a class="header-anchor" href="#define-a-channel" aria-label="Permalink to &quot;Define a channel&quot;">​</a></h2><p>Author <code>agent/channels/&lt;id&gt;.ts</code> with <code>defineChannel</code>. The filename is the channel id, and routes mount under <code>/v1/channels/&lt;id&gt;</code>:</p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { defineChannel, POST } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &quot;@cursor/july/channels&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
2
- <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { z } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &quot;zod&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
3
- <span class="line"></span>
4
- <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> default</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> defineChannel</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
5
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> routes: [</span></span>
6
- <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> POST</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;/message&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, {</span></span>
7
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> description: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;Enqueue a chat turn on this channel&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
8
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> bodySchema: z.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">object</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
9
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> message: z.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">string</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(),</span></span>
10
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> thread: z.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">string</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">().</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">optional</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(),</span></span>
11
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }),</span></span>
12
- <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> handler</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">async</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">_req</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, { </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">send</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">body</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
13
- <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> session</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> await</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> send</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(body.message, {</span></span>
14
- <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // stable key: same thread → same durable session</span></span>
15
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> continuationToken: body.thread,</span></span>
16
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> });</span></span>
17
- <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> Response.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">json</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({ sessionId: session.id });</span></span>
18
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
19
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }),</span></span>
20
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ],</span></span>
21
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> events: {</span></span>
22
- <span class="line"><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &quot;message.completed&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">event</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">channel</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">ctx</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) {</span></span>
23
- <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // deliver the reply back to the surface that owns this channel:</span></span>
24
- <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // post to a webhook, reply in a thread, update a ticket, …</span></span>
25
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
26
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
27
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span></code></pre></div><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">curl</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> -X</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> POST</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> http://127.0.0.1:3000/</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">&lt;</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">slu</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">g</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">&gt;</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">/v1/channels/</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">&lt;</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">i</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">d</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">&gt;</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">/message</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> \\</span></span>
28
- <span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> -H</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &#39;content-type: application/json&#39;</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> \\</span></span>
29
- <span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> -d</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &#39;{&quot;message&quot;:&quot;hello&quot;,&quot;thread&quot;:&quot;ticket-42&quot;}&#39;</span></span></code></pre></div><h2 id="schemas-are-zod-and-required" tabindex="-1">Schemas are Zod, and required <a class="header-anchor" href="#schemas-are-zod-and-required" aria-label="Permalink to &quot;Schemas are Zod, and required&quot;">​</a></h2><p><code>GET</code> routes require a Zod <code>querySchema</code>. <code>POST</code>, <code>PUT</code>, and <code>PATCH</code> require a Zod <code>bodySchema</code>. Compile-time checks enforce this, so plain JSON Schema objects won&#39;t type-check. Use <code>z.object({})</code> or <code>z.unknown()</code> when a surface is intentionally open. The host validates before your handler runs, handlers receive typed <code>args.body</code> and <code>args.query</code>, and empty POST bodies are coerced to <code>{}</code> first.</p><p>Declared schemas also feed <code>GET /v1/info</code>, which adds two things to the playground: a <strong>Try</strong> button on every route, and matching <strong>slash commands</strong> in the composer (a channel <code>drive</code> route becomes <code>/drive …</code>).</p><h2 id="what-a-handler-receives" tabindex="-1">What a handler receives <a class="header-anchor" href="#what-a-handler-receives" aria-label="Permalink to &quot;What a handler receives&quot;">​</a></h2><p>Handlers get the Fetch <code>Request</code> plus an args object:</p><table tabindex="0"><thead><tr><th>Helper</th><th>What it does</th></tr></thead><tbody><tr><td><code>send(message, options?)</code></td><td>Run a model turn on this channel. <code>continuationToken</code> keys the durable session; options can seed <code>workspaceFiles</code>, attach <code>cloud</code> repos, or override <code>auth</code>.</td></tr><tr><td><code>getSession(sessionId)</code></td><td>Look up an existing session</td></tr><tr><td><code>receive(channel, input)</code></td><td>Hand off to another channel (schedules use this)</td></tr><tr><td><code>callTool(name, input, opts?)</code></td><td>Run an authored server tool with no model turn (<a href="./../reference/tools.html#call-a-tool-without-a-model-turn">Tools</a>)</td></tr><tr><td><code>body</code>, <code>query</code>, <code>params</code></td><td>Validated payloads and path params</td></tr><tr><td><code>auth</code></td><td>The <code>AuthContext</code> the route&#39;s auth chain resolved</td></tr><tr><td><code>requestIp</code></td><td>The TCP peer address</td></tr><tr><td><code>host</code></td><td>Shared host services: <code>host.mcp</code>, <code>host.github</code>, <code>host.slack</code>, <code>host.reminders</code></td></tr><tr><td><code>waitUntil(promise)</code></td><td>Background work that outlives the response</td></tr></tbody></table><p>Channel <code>state</code> declares the starting per-session adapter state. It persists across events, and event handlers receive it on <code>channel.state</code>.</p><h2 id="respond-fast-work-in-the-background" tabindex="-1">Respond fast, work in the background <a class="header-anchor" href="#respond-fast-work-in-the-background" aria-label="Permalink to &quot;Respond fast, work in the background&quot;">​</a></h2><p>Webhook senders time out quickly. GitHub gives you about ten seconds. For slow work, ACK immediately and continue in the background:</p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">handler</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">async</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">_req</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, { </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">send</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">waitUntil</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">body</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
30
- <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> waitUntil</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span></span>
31
- <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> send</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">\`Process incoming report: \${</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">body</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">.</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">url</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">}\`</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, {</span></span>
32
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> continuationToken: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">\`report:\${</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">body</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">.</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">id</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">}\`</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
33
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> })</span></span>
34
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> );</span></span>
35
- <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> Response.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">json</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({ accepted: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">true</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }, { status: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">202</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> });</span></span>
36
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">},</span></span></code></pre></div><h2 id="prepare-on-the-host-then-hand-off" tabindex="-1">Prepare on the host, then hand off <a class="header-anchor" href="#prepare-on-the-host-then-hand-off" aria-label="Permalink to &quot;Prepare on the host, then hand off&quot;">​</a></h2><p>The strongest channel pattern: do the deterministic setup in the handler, then hand the model prepared evidence. Fetch the PR with <code>callTool</code>, seed the files it needs, and make the prompt about judgment rather than about finding things:</p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">handler</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">async</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">_req</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, { </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">callTool</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">send</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">body</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
37
- <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> prep</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> await</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> callTool</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;prepare_pr&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, { pr: body.pr });</span></span>
38
- <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (prep.isError) {</span></span>
39
- <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> Response.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">json</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({ ok: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">false</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, error: prep.result }, { status: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">502</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> });</span></span>
40
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
41
- <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> session</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> await</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> send</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;Review the prepared PR under pr/.&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, {</span></span>
42
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> continuationToken: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">\`pr:\${</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">body</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">.</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">pr</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">}\`</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
43
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> });</span></span>
44
- <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> Response.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">json</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({ sessionId: session.id });</span></span>
45
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">},</span></span></code></pre></div><p>This host-prep shape is the change with the largest effect on latency and quality. <a href="./../hillclimbing.html">Hillclimbing</a> lists it first.</p><h2 id="deliver-replies-back-out" tabindex="-1">Deliver replies back out <a class="header-anchor" href="#deliver-replies-back-out" aria-label="Permalink to &quot;Deliver replies back out&quot;">​</a></h2><p>The <code>events</code> map subscribes the channel to stream events for the sessions it owns. Typical wiring: <code>message.completed</code> posts the assistant text back to the caller&#39;s surface, and <code>turn.failed</code> posts an error notice. The full vocabulary is in <a href="./../reference/sessions.html#the-event-vocabulary">Sessions and streaming</a>.</p><h2 id="auth-loopback-by-default-on-purpose" tabindex="-1">Auth: loopback by default, on purpose <a class="header-anchor" href="#auth-loopback-by-default-on-purpose" aria-label="Permalink to &quot;Auth: loopback by default, on purpose&quot;">​</a></h2><p>Every route runs an auth-policy chain (the channel&#39;s <code>auth</code> array). The default is <code>[localDevStrict()]</code>: direct loopback callers only. Requests carrying proxy-forwarding headers (<code>X-Forwarded-For</code>, <code>X-Real-IP</code>, <code>Forwarded</code>, <code>X-Forwarded-Host</code>) are rejected, and a loopback <code>Host</code> header is required. So a tunnel, a same-host reverse proxy, or a DNS-rebinding page can&#39;t silently re-expose the route.</p><p>Before real traffic, author auth explicitly:</p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { bearerAuth, defineChannel, localDevStrict } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &quot;@cursor/july/channels&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
46
- <span class="line"></span>
47
- <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> default</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> defineChannel</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
48
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> auth: [</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">localDevStrict</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(), </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">bearerAuth</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(process.env.</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">WEBHOOK_TOKEN</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> ??</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &quot;&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)],</span></span>
49
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> routes: [</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">/* … */</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">],</span></span>
50
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span></code></pre></div><p>The built-in policies are <code>localDevStrict()</code> (the default), <code>localDev()</code>, <code>loopbackOnly()</code>, <code>bearerAuth(tokenOrVerify)</code>, and <code>allowAll()</code>, and any <code>(request, info) =&gt; AuthContext | null</code> function composes with them. Signature-verified surfaces usually use <code>allowAll()</code> at the route and verify the HMAC in the channel; the GitHub channel with a webhook secret works this way. The details live in <a href="./../reference/channels.html#auth-policies">Channels</a>.</p><p>Server-level flags interact with channel auth. <code>--bearer-token &lt;secret&gt;</code> swaps the default for <code>bearerAuth</code> on every channel that doesn&#39;t author its own chain, and <code>--allow-anonymous</code> swaps it for <code>allowAll()</code> (trusted networks only). Authored <code>auth</code> arrays always win over both.</p><h2 id="test-a-channel" tabindex="-1">Test a channel <a class="header-anchor" href="#test-a-channel" aria-label="Permalink to &quot;Test a channel&quot;">​</a></h2><p>Start with curl and saved payloads under <code>fixtures/</code>. The playground&#39;s <strong>Try</strong> modal covers manual probes. It remembers your last body per endpoint, has Copy curl, and opens the created session on a successful Try. For regression coverage, drive the same behavior through an eval, or keep channel logic deterministic in <code>agent/lib/</code> and unit-test it there. When something looks wrong, read the session&#39;s <code>events.ndjson</code>. The stream is the record of what happened.</p><p>For GitHub specifically, don&#39;t hand-roll fixtures. <code>agentkit github replay</code> synthesizes real-shaped, signed payloads from any PR you can read. See the <a href="./github.html">GitHub guide</a>.</p><h2 id="what-s-next" tabindex="-1">What&#39;s next <a class="header-anchor" href="#what-s-next" aria-label="Permalink to &quot;What&#39;s next&quot;">​</a></h2><p>Continue with these pages:</p><ul><li><a href="./../reference/channels.html">Channels reference</a>: the full authoring API</li><li><a href="./github.html">GitHub</a> and <a href="./slack.html">Slack</a>: the packaged channels</li><li><a href="./../reference/sessions.html">Sessions and streaming</a>: events your channel can subscribe to</li></ul>`,37)])])}const E=i(t,[["render",h]]);export{c as __pageData,E as default};