@cursor/july 0.1.90 → 0.1.91

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 (266) hide show
  1. package/AGENTS.md +8 -0
  2. package/README.md +8 -7
  3. package/dist/channels/slack/channel-watch.d.ts +1 -1
  4. package/dist/channels/slack/channel-watch.js +1 -1
  5. package/dist/channels/slack/slack-channel.js +1 -1
  6. package/dist/channels/slack/types.d.ts +2 -4
  7. package/dist/channels/slack/types.d.ts.map +1 -1
  8. package/dist/docs/404.html +3 -3
  9. package/dist/docs/ab.html +7 -7
  10. package/dist/docs/assets/{ab.md.DYjwREAP.js → ab.md.CVzWxLoB.js} +1 -1
  11. package/dist/docs/assets/{ab.md.DYjwREAP.lean.js → ab.md.CVzWxLoB.lean.js} +1 -1
  12. package/dist/docs/assets/{app.wiNkt6G7.js → app.Bci6CM9E.js} +1 -1
  13. package/dist/docs/assets/{building-with-agents.md.PeZaZA1P.js → building-with-agents.md.DH8A_cHA.js} +1 -1
  14. package/dist/docs/assets/{building-with-agents.md.PeZaZA1P.lean.js → building-with-agents.md.DH8A_cHA.lean.js} +1 -1
  15. package/dist/docs/assets/chunks/@localSearchIndexroot.Dv-Q0XtU.js +1 -0
  16. package/dist/docs/assets/chunks/{VPLocalSearchBox.ByhUGu47.js → VPLocalSearchBox.BCPT6xA-.js} +1 -1
  17. package/dist/docs/assets/chunks/{framework.CAZyNGu9.js → framework.BCISBCiQ.js} +1 -1
  18. package/dist/docs/assets/chunks/theme.BEA8BF3c.js +2 -0
  19. package/dist/docs/assets/{concepts.md.2NfkGjqM.js → concepts.md.CRfU3bVg.js} +1 -1
  20. package/dist/docs/assets/{concepts.md.2NfkGjqM.lean.js → concepts.md.CRfU3bVg.lean.js} +1 -1
  21. package/dist/docs/assets/{deployment.md.B8kW-h7P.js → deployment.md.DX_hc3ze.js} +6 -5
  22. package/dist/docs/assets/{deployment.md.B8kW-h7P.lean.js → deployment.md.DX_hc3ze.lean.js} +1 -1
  23. package/dist/docs/assets/{evals.md.CVe_O75-.js → evals.md.a0SMN6r9.js} +3 -3
  24. package/dist/docs/assets/{evals.md.CVe_O75-.lean.js → evals.md.a0SMN6r9.lean.js} +1 -1
  25. package/dist/docs/assets/{example-agents_approval-buddy.md.CIiZ9coo.js → example-agents_approval-buddy.md.DNL83puR.js} +1 -1
  26. package/dist/docs/assets/{example-agents_approval-buddy.md.CIiZ9coo.lean.js → example-agents_approval-buddy.md.DNL83puR.lean.js} +1 -1
  27. package/dist/docs/assets/{example-agents_benny.md.B-LIDGja.js → example-agents_benny.md.C40vHRLc.js} +1 -1
  28. package/dist/docs/assets/{example-agents_benny.md.B-LIDGja.lean.js → example-agents_benny.md.C40vHRLc.lean.js} +1 -1
  29. package/dist/docs/assets/{example-agents_bugbot.md.Dp5JqHSQ.js → example-agents_bugbot.md.BRGMi9O2.js} +1 -1
  30. package/dist/docs/assets/{example-agents_bugbot.md.Dp5JqHSQ.lean.js → example-agents_bugbot.md.BRGMi9O2.lean.js} +1 -1
  31. package/dist/docs/assets/{example-agents_codebase-wiki.md.D-lteFf0.js → example-agents_codebase-wiki.md.Dftj_tPp.js} +1 -1
  32. package/dist/docs/assets/{example-agents_codebase-wiki.md.D-lteFf0.lean.js → example-agents_codebase-wiki.md.Dftj_tPp.lean.js} +1 -1
  33. package/dist/docs/assets/{example-agents_codeowners-review.md.BU2ZXLf-.js → example-agents_codeowners-review.md.Bfta-lBU.js} +1 -1
  34. package/dist/docs/assets/{example-agents_codeowners-review.md.BU2ZXLf-.lean.js → example-agents_codeowners-review.md.Bfta-lBU.lean.js} +1 -1
  35. package/dist/docs/assets/{example-agents_concierge.md.DA2al_NK.js → example-agents_concierge.md.MrKpQndp.js} +1 -1
  36. package/dist/docs/assets/{example-agents_concierge.md.DA2al_NK.lean.js → example-agents_concierge.md.MrKpQndp.lean.js} +1 -1
  37. package/dist/docs/assets/{example-agents_fsd.md.ZeGEpAw_.js → example-agents_fsd.md.ZWHWWZPE.js} +1 -1
  38. package/dist/docs/assets/{example-agents_fsd.md.ZeGEpAw_.lean.js → example-agents_fsd.md.ZWHWWZPE.lean.js} +1 -1
  39. package/dist/docs/assets/example-agents_index.md.QZ8mhr6n.js +2 -0
  40. package/dist/docs/assets/{example-agents_index.md.xmJ87d_3.lean.js → example-agents_index.md.QZ8mhr6n.lean.js} +1 -1
  41. package/dist/docs/assets/{example-agents_knowledge-base.md.IneynQSR.js → example-agents_knowledge-base.md.DqKqHQ9u.js} +1 -1
  42. package/dist/docs/assets/{example-agents_knowledge-base.md.IneynQSR.lean.js → example-agents_knowledge-base.md.DqKqHQ9u.lean.js} +1 -1
  43. package/dist/docs/assets/{example-agents_oncall.md.CBmyuAKc.js → example-agents_oncall.md.DK4XkYTd.js} +1 -1
  44. package/dist/docs/assets/{example-agents_oncall.md.CBmyuAKc.lean.js → example-agents_oncall.md.DK4XkYTd.lean.js} +1 -1
  45. package/dist/docs/assets/{example-agents_security-reviewer.md.DBL1TwtP.js → example-agents_security-reviewer.md.Bai6D0Ee.js} +4 -4
  46. package/dist/docs/assets/{example-agents_security-reviewer.md.DBL1TwtP.lean.js → example-agents_security-reviewer.md.Bai6D0Ee.lean.js} +1 -1
  47. package/dist/docs/assets/{example-agents_slack-agent.md.06jQXTAI.js → example-agents_slack-agent.md.D7Kdj5BV.js} +1 -1
  48. package/dist/docs/assets/{example-agents_slack-agent.md.06jQXTAI.lean.js → example-agents_slack-agent.md.D7Kdj5BV.lean.js} +1 -1
  49. package/dist/docs/assets/{example-agents_weather-agent.md.DC3lINjo.js → example-agents_weather-agent.md.lVEAbWFf.js} +5 -5
  50. package/dist/docs/assets/example-agents_weather-agent.md.lVEAbWFf.lean.js +1 -0
  51. package/dist/docs/assets/{guides_agent-to-agent.md.Bmbxy-FA.js → guides_agent-to-agent.md.BCeVdJRJ.js} +1 -1
  52. package/dist/docs/assets/{guides_agent-to-agent.md.Bmbxy-FA.lean.js → guides_agent-to-agent.md.BCeVdJRJ.lean.js} +1 -1
  53. package/dist/docs/assets/{guides_cloud-runtime.md.CbklWfzh.js → guides_cloud-runtime.md.BSMLIBHr.js} +1 -1
  54. package/dist/docs/assets/{guides_cloud-runtime.md.CbklWfzh.lean.js → guides_cloud-runtime.md.BSMLIBHr.lean.js} +1 -1
  55. package/dist/docs/assets/{guides_convert-automation.md.BhMzTkE5.js → guides_convert-automation.md.D06eIzea.js} +1 -1
  56. package/dist/docs/assets/{guides_convert-automation.md.BhMzTkE5.lean.js → guides_convert-automation.md.D06eIzea.lean.js} +1 -1
  57. package/dist/docs/assets/{guides_github.md.CLLQJKRB.js → guides_github.md.Cdt1s2QC.js} +4 -4
  58. package/dist/docs/assets/{guides_github.md.CLLQJKRB.lean.js → guides_github.md.Cdt1s2QC.lean.js} +1 -1
  59. package/dist/docs/assets/{guides_human-in-the-loop.md.Cf8kIIqC.js → guides_human-in-the-loop.md.By1G2T3_.js} +1 -1
  60. package/dist/docs/assets/{guides_human-in-the-loop.md.Cf8kIIqC.lean.js → guides_human-in-the-loop.md.By1G2T3_.lean.js} +1 -1
  61. package/dist/docs/assets/{guides_mcp-oauth.md.CzEB6RaG.js → guides_mcp-oauth.md.Du0f7pGU.js} +1 -1
  62. package/dist/docs/assets/{guides_mcp-oauth.md.CzEB6RaG.lean.js → guides_mcp-oauth.md.Du0f7pGU.lean.js} +1 -1
  63. package/dist/docs/assets/{guides_opentelemetry.md.Csn7ZI25.js → guides_opentelemetry.md.bmPmkvJu.js} +1 -1
  64. package/dist/docs/assets/{guides_opentelemetry.md.Csn7ZI25.lean.js → guides_opentelemetry.md.bmPmkvJu.lean.js} +1 -1
  65. package/dist/docs/assets/{guides_slack.md.DP4H75WP.js → guides_slack.md.DiUmk_Oi.js} +5 -5
  66. package/dist/docs/assets/{guides_slack.md.DP4H75WP.lean.js → guides_slack.md.DiUmk_Oi.lean.js} +1 -1
  67. package/dist/docs/assets/{guides_webhooks.md.DB-r_er9.js → guides_webhooks.md.BpnIdO0i.js} +5 -6
  68. package/dist/docs/assets/{guides_webhooks.md.DB-r_er9.lean.js → guides_webhooks.md.BpnIdO0i.lean.js} +1 -1
  69. package/dist/docs/assets/{hillclimbing.md.yXqdlv2R.js → hillclimbing.md.ywF3yDAd.js} +1 -1
  70. package/dist/docs/assets/{hillclimbing.md.yXqdlv2R.lean.js → hillclimbing.md.ywF3yDAd.lean.js} +1 -1
  71. package/dist/docs/assets/index.md.BAaMXLFd.js +5 -0
  72. package/dist/docs/assets/{index.md.DhRHS_-L.lean.js → index.md.BAaMXLFd.lean.js} +1 -1
  73. package/dist/docs/assets/{quickstart.md.DZxBu44y.js → quickstart.md.DsrarzEg.js} +1 -1
  74. package/dist/docs/assets/{quickstart.md.DZxBu44y.lean.js → quickstart.md.DsrarzEg.lean.js} +1 -1
  75. package/dist/docs/assets/{reference_agent-config.md.CTWp4DnU.js → reference_agent-config.md.Bqylgw50.js} +1 -1
  76. package/dist/docs/assets/{reference_agent-config.md.CTWp4DnU.lean.js → reference_agent-config.md.Bqylgw50.lean.js} +1 -1
  77. package/dist/docs/assets/{reference_artifacts.md.BGG4bZo-.js → reference_artifacts.md.Dior32Qw.js} +1 -1
  78. package/dist/docs/assets/{reference_artifacts.md.BGG4bZo-.lean.js → reference_artifacts.md.Dior32Qw.lean.js} +1 -1
  79. package/dist/docs/assets/{reference_channels.md.CboFd5IH.js → reference_channels.md.DQZjCnyh.js} +2 -2
  80. package/dist/docs/assets/{reference_channels.md.CboFd5IH.lean.js → reference_channels.md.DQZjCnyh.lean.js} +1 -1
  81. package/dist/docs/assets/{reference_cli.md.TAaYU8br.js → reference_cli.md.B7GkAJRC.js} +8 -7
  82. package/dist/docs/assets/{reference_cli.md.TAaYU8br.lean.js → reference_cli.md.B7GkAJRC.lean.js} +1 -1
  83. package/dist/docs/assets/{reference_connections.md.Cu3N-S3Q.js → reference_connections.md.DYidrb-j.js} +5 -5
  84. package/dist/docs/assets/{reference_connections.md.Cu3N-S3Q.lean.js → reference_connections.md.DYidrb-j.lean.js} +1 -1
  85. package/dist/docs/assets/{reference_hooks.md.DJE5DXcT.js → reference_hooks.md.B9FSgdDe.js} +1 -1
  86. package/dist/docs/assets/{reference_hooks.md.DJE5DXcT.lean.js → reference_hooks.md.B9FSgdDe.lean.js} +1 -1
  87. package/dist/docs/assets/{reference_http-api.md.DMbdFGVQ.js → reference_http-api.md.CSHVobzG.js} +4 -4
  88. package/dist/docs/assets/{reference_http-api.md.DMbdFGVQ.lean.js → reference_http-api.md.CSHVobzG.lean.js} +1 -1
  89. package/dist/docs/assets/{reference_instructions.md.CgoV-YEb.js → reference_instructions.md.DhNCOl7r.js} +1 -1
  90. package/dist/docs/assets/{reference_instructions.md.CgoV-YEb.lean.js → reference_instructions.md.DhNCOl7r.lean.js} +1 -1
  91. package/dist/docs/assets/{reference_playground.md.CPZhfYaO.js → reference_playground.md.Dfb92yQf.js} +1 -1
  92. package/dist/docs/assets/{reference_playground.md.CPZhfYaO.lean.js → reference_playground.md.Dfb92yQf.lean.js} +1 -1
  93. package/dist/docs/assets/{reference_project-layout.md.CueaKpjr.js → reference_project-layout.md.CwkSbEWT.js} +1 -1
  94. package/dist/docs/assets/{reference_project-layout.md.CueaKpjr.lean.js → reference_project-layout.md.CwkSbEWT.lean.js} +1 -1
  95. package/dist/docs/assets/{reference_prompt.md.BaiweQxE.js → reference_prompt.md.DZUMtLPD.js} +1 -1
  96. package/dist/docs/assets/{reference_prompt.md.BaiweQxE.lean.js → reference_prompt.md.DZUMtLPD.lean.js} +1 -1
  97. package/dist/docs/assets/{reference_schedules.md.gmfYzf_I.js → reference_schedules.md.DNipebiG.js} +1 -1
  98. package/dist/docs/assets/{reference_schedules.md.gmfYzf_I.lean.js → reference_schedules.md.DNipebiG.lean.js} +1 -1
  99. package/dist/docs/assets/{reference_sessions.md.B0DdlM-K.js → reference_sessions.md.tUFzz98S.js} +1 -1
  100. package/dist/docs/assets/{reference_sessions.md.B0DdlM-K.lean.js → reference_sessions.md.tUFzz98S.lean.js} +1 -1
  101. package/dist/docs/assets/{reference_skills.md.BRF2nDv9.js → reference_skills.md.B5ZEuHfG.js} +1 -1
  102. package/dist/docs/assets/{reference_skills.md.BRF2nDv9.lean.js → reference_skills.md.B5ZEuHfG.lean.js} +1 -1
  103. package/dist/docs/assets/{reference_subagents.md.DSrGLIuB.js → reference_subagents.md.Xoav0AII.js} +1 -1
  104. package/dist/docs/assets/{reference_subagents.md.DSrGLIuB.lean.js → reference_subagents.md.Xoav0AII.lean.js} +1 -1
  105. package/dist/docs/assets/{reference_tools.md.XmeFP_3d.js → reference_tools.md.wpaJtHn6.js} +2 -3
  106. package/dist/docs/assets/{reference_tools.md.XmeFP_3d.lean.js → reference_tools.md.wpaJtHn6.lean.js} +1 -1
  107. package/dist/docs/assets/{scaffolding-agents.md.BpMFXv2J.js → scaffolding-agents.md.CRDDUtYJ.js} +1 -1
  108. package/dist/docs/assets/{scaffolding-agents.md.BpMFXv2J.lean.js → scaffolding-agents.md.CRDDUtYJ.lean.js} +1 -1
  109. package/dist/docs/assets/{storage.md.ks1u64_R.js → storage.md.JbjlHWZ6.js} +1 -1
  110. package/dist/docs/assets/{storage.md.ks1u64_R.lean.js → storage.md.JbjlHWZ6.lean.js} +1 -1
  111. package/dist/docs/assets/{style.kTsvp4pE.css → style.BRuM8477.css} +1 -1
  112. package/dist/docs/assets/{templates_agentic-owners.md.BkTLORaU.js → templates_agentic-owners.md.DSJSIpWU.js} +1 -1
  113. package/dist/docs/assets/{templates_agentic-owners.md.BkTLORaU.lean.js → templates_agentic-owners.md.DSJSIpWU.lean.js} +1 -1
  114. package/dist/docs/assets/{templates_demo.md.Bgd6MBaZ.js → templates_demo.md.DhFcWN6j.js} +1 -1
  115. package/dist/docs/assets/{templates_demo.md.Bgd6MBaZ.lean.js → templates_demo.md.DhFcWN6j.lean.js} +1 -1
  116. package/dist/docs/assets/{templates_pr-autofixer.md.DcmoeUNZ.js → templates_pr-autofixer.md.1HAR3RXE.js} +1 -1
  117. package/dist/docs/assets/{templates_pr-autofixer.md.DcmoeUNZ.lean.js → templates_pr-autofixer.md.1HAR3RXE.lean.js} +1 -1
  118. package/dist/docs/assets/{templates_security-reviewer.md.C0yIUaYs.js → templates_security-reviewer.md.ByFyRta2.js} +1 -1
  119. package/dist/docs/assets/{templates_security-reviewer.md.C0yIUaYs.lean.js → templates_security-reviewer.md.ByFyRta2.lean.js} +1 -1
  120. package/dist/docs/assets/{templates_triage.md.DWuQ1bZz.js → templates_triage.md.CVlpctKS.js} +2 -2
  121. package/dist/docs/assets/{templates_triage.md.DWuQ1bZz.lean.js → templates_triage.md.CVlpctKS.lean.js} +1 -1
  122. package/dist/docs/assets/troubleshooting.md.DYECCZiJ.js +1 -0
  123. package/dist/docs/assets/{troubleshooting.md.KgmmaCgw.lean.js → troubleshooting.md.DYECCZiJ.lean.js} +1 -1
  124. package/dist/docs/building-with-agents.html +7 -7
  125. package/dist/docs/concepts.html +7 -7
  126. package/dist/docs/deployment.html +11 -10
  127. package/dist/docs/evals.html +8 -8
  128. package/dist/docs/example-agents/approval-buddy.html +7 -7
  129. package/dist/docs/example-agents/benny.html +7 -7
  130. package/dist/docs/example-agents/bugbot.html +7 -7
  131. package/dist/docs/example-agents/codebase-wiki.html +7 -7
  132. package/dist/docs/example-agents/codeowners-review.html +7 -7
  133. package/dist/docs/example-agents/concierge.html +7 -7
  134. package/dist/docs/example-agents/fsd.html +7 -7
  135. package/dist/docs/example-agents/index.html +7 -7
  136. package/dist/docs/example-agents/knowledge-base.html +7 -7
  137. package/dist/docs/example-agents/oncall.html +7 -7
  138. package/dist/docs/example-agents/security-reviewer.html +10 -10
  139. package/dist/docs/example-agents/slack-agent.html +7 -7
  140. package/dist/docs/example-agents/weather-agent.html +12 -12
  141. package/dist/docs/guides/agent-to-agent.html +7 -7
  142. package/dist/docs/guides/cloud-runtime.html +7 -7
  143. package/dist/docs/guides/convert-automation.html +7 -7
  144. package/dist/docs/guides/github.html +9 -9
  145. package/dist/docs/guides/human-in-the-loop.html +7 -7
  146. package/dist/docs/guides/mcp-oauth.html +7 -7
  147. package/dist/docs/guides/opentelemetry.html +7 -7
  148. package/dist/docs/guides/slack.html +10 -10
  149. package/dist/docs/guides/webhooks.html +10 -11
  150. package/dist/docs/hashmap.json +1 -1
  151. package/dist/docs/hillclimbing.html +7 -7
  152. package/dist/docs/index.html +8 -8
  153. package/dist/docs/quickstart.html +7 -7
  154. package/dist/docs/reference/agent-config.html +7 -7
  155. package/dist/docs/reference/artifacts.html +7 -7
  156. package/dist/docs/reference/channels.html +8 -8
  157. package/dist/docs/reference/cli.html +13 -12
  158. package/dist/docs/reference/connections.html +10 -10
  159. package/dist/docs/reference/hooks.html +7 -7
  160. package/dist/docs/reference/http-api.html +10 -10
  161. package/dist/docs/reference/instructions.html +7 -7
  162. package/dist/docs/reference/playground.html +7 -7
  163. package/dist/docs/reference/project-layout.html +7 -7
  164. package/dist/docs/reference/prompt.html +7 -7
  165. package/dist/docs/reference/schedules.html +7 -7
  166. package/dist/docs/reference/sessions.html +7 -7
  167. package/dist/docs/reference/skills.html +7 -7
  168. package/dist/docs/reference/subagents.html +7 -7
  169. package/dist/docs/reference/tools.html +8 -9
  170. package/dist/docs/scaffolding-agents.html +7 -7
  171. package/dist/docs/storage.html +7 -7
  172. package/dist/docs/templates/agentic-owners.html +7 -7
  173. package/dist/docs/templates/demo.html +7 -7
  174. package/dist/docs/templates/pr-autofixer.html +7 -7
  175. package/dist/docs/templates/security-reviewer.html +7 -7
  176. package/dist/docs/templates/triage.html +8 -8
  177. package/dist/docs/troubleshooting.html +7 -7
  178. package/dist/internal/cli-deploy.d.ts.map +1 -1
  179. package/dist/internal/cli-deploy.js +21 -3
  180. package/dist/internal/cursor-agent-template.d.ts +1 -1
  181. package/dist/internal/cursor-agent-template.d.ts.map +1 -1
  182. package/dist/internal/cursor-agent-template.js +1 -0
  183. package/dist/internal/deploy-client.d.ts +18 -0
  184. package/dist/internal/deploy-client.d.ts.map +1 -1
  185. package/dist/internal/deploy-client.js +25 -1
  186. package/dist/internal/deploy-manifest.d.ts.map +1 -1
  187. package/dist/internal/deploy-manifest.js +5 -1
  188. package/dist/internal/discovery.d.ts +5 -1
  189. package/dist/internal/discovery.d.ts.map +1 -1
  190. package/dist/internal/discovery.js +16 -0
  191. package/dist/internal/http-channel.d.ts +2 -2
  192. package/dist/internal/http-channel.d.ts.map +1 -1
  193. package/dist/internal/http-channel.js +11 -31
  194. package/dist/internal/init-project.d.ts.map +1 -1
  195. package/dist/internal/init-project.js +2 -0
  196. package/dist/internal/session-engine.d.ts +8 -0
  197. package/dist/internal/session-engine.d.ts.map +1 -1
  198. package/dist/internal/session-engine.js +47 -5
  199. package/dist/playground/assets/index-D9N7-q97.css +1 -0
  200. package/dist/playground/assets/{index-DxapiDj_.js → index-DDvyC2z6.js} +49 -49
  201. package/dist/playground/index.html +2 -2
  202. package/dist/types.d.ts +8 -5
  203. package/dist/types.d.ts.map +1 -1
  204. package/docs/README.md +3 -1
  205. package/docs/concepts.md +1 -1
  206. package/docs/deployment.md +9 -6
  207. package/docs/evals.md +1 -5
  208. package/docs/example-agents/codebase-wiki.md +2 -3
  209. package/docs/example-agents/fsd.md +1 -1
  210. package/docs/example-agents/index.md +2 -2
  211. package/docs/example-agents/knowledge-base.md +3 -3
  212. package/docs/example-agents/security-reviewer.md +17 -48
  213. package/docs/example-agents/weather-agent.md +14 -45
  214. package/docs/guides/github.md +7 -4
  215. package/docs/guides/slack.md +7 -2
  216. package/docs/guides/webhooks.md +12 -15
  217. package/docs/reference/channels.md +4 -0
  218. package/docs/reference/cli.md +21 -7
  219. package/docs/reference/connections.md +13 -32
  220. package/docs/reference/http-api.md +14 -9
  221. package/docs/reference/tools.md +1 -3
  222. package/docs/templates/triage.md +3 -5
  223. package/docs/troubleshooting.md +1 -1
  224. package/package.json +1 -1
  225. package/skills/create-agent/SKILL.md +6 -7
  226. package/skills/framework-map/SKILL.md +6 -6
  227. package/skills/setup-slack/SKILL.md +1 -1
  228. package/src/channels/slack/channel-watch.ts +1 -1
  229. package/src/channels/slack/slack-channel.ts +1 -1
  230. package/src/channels/slack/types.ts +2 -4
  231. package/src/internal/cli-deploy.ts +27 -7
  232. package/src/internal/cursor-agent-template.ts +1 -0
  233. package/src/internal/deploy-client.ts +40 -1
  234. package/src/internal/deploy-manifest.ts +10 -1
  235. package/src/internal/discovery.ts +20 -0
  236. package/src/internal/http-channel.ts +14 -41
  237. package/src/internal/init-project.ts +2 -0
  238. package/src/internal/session-engine.ts +58 -8
  239. package/src/types.ts +8 -5
  240. package/templates/security-help/README.md +37 -0
  241. package/templates/security-help/agent/agent.ts +18 -0
  242. package/templates/security-help/agent/channels/github.ts +13 -0
  243. package/templates/security-help/agent/channels/slack.ts +89 -0
  244. package/templates/security-help/agent/instructions.md +20 -0
  245. package/templates/security-help/agent/knowledge/faq/approvals.md +5 -0
  246. package/templates/security-help/agent/knowledge/faq/channels.md +6 -0
  247. package/templates/security-help/agent/knowledge/faq/phishing.md +10 -0
  248. package/templates/security-help/agent/lib/pr-first-pass.ts +42 -0
  249. package/templates/security-help/agent/lib/repos.ts +5 -0
  250. package/templates/security-help/agent/skills/access-request.md +10 -0
  251. package/templates/security-help/agent/skills/security-first-pass.md +15 -0
  252. package/templates/security-help/agent/skills/security-playbooks.md +12 -0
  253. package/templates/security-help/agent/skills/security-pr-first-pass.md +12 -0
  254. package/templates/security-help/evals/evals.config.ts +5 -0
  255. package/templates/security-help/evals/security-help.eval.ts +53 -0
  256. package/templates/security-help/init.json +31 -0
  257. package/templates/security-help/package.json +18 -0
  258. package/templates/security-help/tsconfig.json +12 -0
  259. package/templates/triage/agent/channels/webhook.ts +2 -2
  260. package/dist/docs/assets/chunks/@localSearchIndexroot.FV0R6kOb.js +0 -1
  261. package/dist/docs/assets/chunks/theme.Dx7j_-0n.js +0 -2
  262. package/dist/docs/assets/example-agents_index.md.xmJ87d_3.js +0 -2
  263. package/dist/docs/assets/example-agents_weather-agent.md.DC3lINjo.lean.js +0 -1
  264. package/dist/docs/assets/index.md.DhRHS_-L.js +0 -5
  265. package/dist/docs/assets/troubleshooting.md.KgmmaCgw.js +0 -1
  266. package/dist/playground/assets/index-BpVS-paP.css +0 -1
@@ -1,4 +1,4 @@
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: Cursor-hosted connection, a dedicated Socket Mode app via the dashboard wizard, or a manual manifest import.","frontmatter":{"title":"Slack","description":"Put the agent in Slack: Cursor-hosted connection, a dedicated Socket Mode app via the dashboard wizard, or a manual manifest import."},"headers":[],"relativePath":"guides/slack.md","filePath":"guides/slack.md"}'),n={name:"guides/slack.md"};function h(o,s,l,p,r,d){return i(),e("div",null,[...s[0]||(s[0]=[t(`<h1 id="slack-agents" tabindex="-1">Slack agents <a class="header-anchor" href="#slack-agents" aria-label="Permalink to &quot;Slack agents&quot;">​</a></h1><p>The Slack channel puts your agent in Slack. Two products: the Cursor-hosted connection (<code>cursorAccount: true</code>), or a dedicated Socket Mode app created in the dashboard wizard (<code>agent-sdk slack create</code>). To own the Slack app yourself, run <code>agent-sdk slack init --manual</code> and paste the manifests at <a href="https://api.slack.com/apps" target="_blank" rel="noreferrer">api.slack.com</a>. Socket Mode has no public Request URL. Replies stream in threads, with tool &quot;thinking&quot; steps, suggested prompts, and opt-in approval buttons.</p><p>The companion skill is <a href="./../../skills/setup-slack/SKILL.html"><code>skills/setup-slack/SKILL.md</code></a>.</p><h2 id="define-the-channel" tabindex="-1">Define the channel <a class="header-anchor" href="#define-the-channel" aria-label="Permalink to &quot;Define the channel&quot;">​</a></h2><p>Author <code>agent/channels/slack.ts</code> with <code>slackChannel()</code> from <code>@cursor/july/channels/slack</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;"> { slackChannel } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &quot;@cursor/july/channels/slack&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
1
+ import{_ as a,c as e,o as i,ag as t}from"./chunks/framework.BCISBCiQ.js";const c=JSON.parse('{"title":"Slack","description":"Put the agent in Slack: Cursor-hosted connection, a dedicated Socket Mode app via the dashboard wizard, or a manual manifest import.","frontmatter":{"title":"Slack","description":"Put the agent in Slack: Cursor-hosted connection, a dedicated Socket Mode app via the dashboard wizard, or a manual manifest import."},"headers":[],"relativePath":"guides/slack.md","filePath":"guides/slack.md"}'),n={name:"guides/slack.md"};function h(o,s,l,p,r,d){return i(),e("div",null,[...s[0]||(s[0]=[t(`<h1 id="slack-agents" tabindex="-1">Slack agents <a class="header-anchor" href="#slack-agents" aria-label="Permalink to &quot;Slack agents&quot;">​</a></h1><p>The Slack channel puts your agent in Slack. Two products: the Cursor-hosted connection (<code>cursorAccount: true</code>), or a dedicated Socket Mode app created in the dashboard wizard (<code>agent-sdk slack create</code>). To own the Slack app yourself, run <code>agent-sdk slack init --manual</code> and paste the manifests at <a href="https://api.slack.com/apps" target="_blank" rel="noreferrer">api.slack.com</a>. Socket Mode has no public Request URL. Replies stream in threads, with tool &quot;thinking&quot; steps, suggested prompts, and opt-in approval buttons.</p><p>The companion skill is <a href="./../../skills/setup-slack/SKILL.html"><code>skills/setup-slack/SKILL.md</code></a>.</p><h2 id="define-the-channel" tabindex="-1">Define the channel <a class="header-anchor" href="#define-the-channel" aria-label="Permalink to &quot;Define the channel&quot;">​</a></h2><p>Author <code>agent/channels/slack.ts</code> with <code>slackChannel()</code> from <code>@cursor/july/channels/slack</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;"> { slackChannel } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &quot;@cursor/july/channels/slack&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
2
2
  <span class="line"></span>
3
3
  <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// Single agent: reads SLACK_BOT_TOKEN + SLACK_APP_TOKEN</span></span>
4
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;"> slackChannel</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">();</span></span>
@@ -11,7 +11,7 @@ import{_ as a,c as e,o as i,ag as t}from"./chunks/framework.CAZyNGu9.js";const c
11
11
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> cursorAccount: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">true</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
12
12
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> agentName: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;Weatherbot&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// single token — no spaces; defaults from mount slug (PascalCase)</span></span>
13
13
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> agentIcon: { emoji: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;:robot_face:&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
14
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span></code></pre></div><p>Sign the host in (<code>agent-sdk login</code> or <code>CURSOR_API_KEY</code>), then mention the agent in Slack as <code>@Cursor Weatherbot …</code>. Thread replies and DMs keep going to the same agent. Messages appear as the Cursor app under that agent&#39;s name and icon, with live updates as the turn progresses.</p><p>Use a dedicated Socket Mode Slack app when you need your own bot user, channel watching (<code>engagement.channelPosts</code>), or approval buttons. On <code>cursorAccount</code>, agents must be explicitly addressed (@mention, DM, or claimed-thread reply). Channel watching and <code>toolApprovals</code> / <code>interactivity</code> are Socket Mode only; the Cursor connection does not relay Block Kit clicks. Agent names must be unique on the host; an unmatched <code>@Cursor &lt;name&gt;</code> stays on Cursor&#39;s normal Slack agent.</p><h2 id="control-who-can-message-the-agent" tabindex="-1">Control who can message the agent <a class="header-anchor" href="#control-who-can-message-the-agent" aria-label="Permalink to &quot;Control who can message the agent&quot;">​</a></h2><p>External senders are blocked by default. Slack Connect users, guests, and people whose home workspace is not the install team never reach the handler. That applies to Socket Mode and <code>cursorAccount: true</code>. Set <code>blockExternals: false</code> only when the agent should serve people outside your org:</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;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> default</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> slackChannel</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
14
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span></code></pre></div><p>Sign the host in (<code>agent-sdk login</code> or <code>CURSOR_API_KEY</code>), then mention the agent in Slack as <code>@Cursor Weatherbot …</code>. Thread replies and DMs keep going to the same agent. Messages appear as the Cursor app under that agent&#39;s name and icon. Slack shows its working status, then posts one final reply.</p><p>Use a dedicated Socket Mode Slack app when you need your own bot user, channel watching (<code>engagement.channelPosts</code>), or approval buttons. On <code>cursorAccount</code>, agents must be explicitly addressed (@mention, DM, or claimed-thread reply). Channel watching and <code>toolApprovals</code> / <code>interactivity</code> are Socket Mode only; the Cursor connection does not relay Block Kit clicks. Agent names must be unique on the host; an unmatched <code>@Cursor &lt;name&gt;</code> stays on Cursor&#39;s normal Slack agent.</p><h2 id="control-who-can-message-the-agent" tabindex="-1">Control who can message the agent <a class="header-anchor" href="#control-who-can-message-the-agent" aria-label="Permalink to &quot;Control who can message the agent&quot;">​</a></h2><p>External senders are blocked by default. Slack Connect users, guests, and people whose home workspace is not the install team never reach the handler. That applies to Socket Mode and <code>cursorAccount: true</code>. Set <code>blockExternals: false</code> only when the agent should serve people outside your org:</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;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> default</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> slackChannel</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
15
15
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> policy: { blockExternals: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">false</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
16
16
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span></code></pre></div><p>Sessions are thread-scoped by default, so anyone in the thread can continue. Restrict follow-ups to the person who started the session with <code>respondTo: &quot;author&quot;</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;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> default</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> slackChannel</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
17
17
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> policy: { respondTo: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;author&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
@@ -22,7 +22,7 @@ import{_ as a,c as e,o as i,ag as t}from"./chunks/framework.CAZyNGu9.js";const c
22
22
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> engagement: {</span></span>
23
23
  <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // mentions / directMessages default to true</span></span>
24
24
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> channelPosts: {</span></span>
25
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> allow: [</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;#triage-alerts&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">], </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// explicit allowlist; no wildcard exists</span></span>
25
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> allow: [</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;#triage-alerts&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">], </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// use [&quot;*&quot;] for every joined channel</span></span>
26
26
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> posts: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;top-level&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// default: thread replies never dispatch</span></span>
27
27
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> debounceMs: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">15_000</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// optional: let rapid edits settle</span></span>
28
28
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> includeBotPosts: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">false</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// default: bot-authored posts never dispatch</span></span>
@@ -32,7 +32,7 @@ import{_ as a,c as e,o as i,ag as t}from"./chunks/framework.CAZyNGu9.js";const c
32
32
  <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // same contract as onAppMention: return null to skip</span></span>
33
33
  <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> message.markdown.</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">length</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> &gt;</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> 20</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> ?</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {} </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">:</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> null</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
34
34
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
35
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span></code></pre></div><p>Channel watching needs the <code>message.channels</code> / <code>message.groups</code> events on the Slack app (Socket Mode only; not available with <code>cursorAccount: true</code>). Pass <code>--channel-posts</code> on <code>slack create</code> or <code>slack init --manual</code>. The bot must also be a member of each watched channel.</p><p>Set <code>includeBotPosts: true</code> when the posts worth watching come from bots: alert feeds, webhook integrations, or other agents posting notes. The watching app&#39;s own posts stay dropped either way, matched by the <code>bot_id</code> and bot user id from <code>auth.test</code>, so an agent can never dispatch on its own replies. The <a href="./../example-agents/oncall.html">alert investigator example</a> watches a bot-fed alerts channel this way.</p><h2 id="prepare-work-on-the-host" tabindex="-1">Prepare work on the host <a class="header-anchor" href="#prepare-work-on-the-host" aria-label="Permalink to &quot;Prepare work on the host&quot;">​</a></h2><p>Mention and DM handlers may return a prepared <code>message</code>, <code>workspaceFiles</code>, or <code>cloud</code> block. It&#39;s the same host-prep pattern as <a href="./webhooks.html#prepare-on-the-host-then-hand-off">custom channels</a>. PR agents use it: extract a PR URL from the mention text and run the same host path as the HTTP channel.</p><h2 id="add-approval-buttons" tabindex="-1">Add approval buttons <a class="header-anchor" href="#add-approval-buttons" aria-label="Permalink to &quot;Add approval buttons&quot;">​</a></h2><p>Tools with <code>needsApproval</code> park until a person decides. Route that through Slack with one flag:</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;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> default</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> slackChannel</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
35
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span></code></pre></div><p>Channel watching needs the <code>message.channels</code> / <code>message.groups</code> events on the Slack app (Socket Mode only; not available with <code>cursorAccount: true</code>). Pass <code>--channel-posts</code> on <code>slack create</code> or <code>slack init --manual</code>. The bot must also be a member of each watched channel.</p><p>Set <code>allow: [&quot;*&quot;]</code> to watch every channel the bot has joined.</p><p>Set <code>includeBotPosts: true</code> when the posts worth watching come from bots: alert feeds, webhook integrations, or other agents posting notes. The watching app&#39;s own posts stay dropped either way, matched by the <code>bot_id</code> and bot user id from <code>auth.test</code>, so an agent can never dispatch on its own replies. The <a href="./../example-agents/oncall.html">alert investigator example</a> watches a bot-fed alerts channel this way.</p><h2 id="prepare-work-on-the-host" tabindex="-1">Prepare work on the host <a class="header-anchor" href="#prepare-work-on-the-host" aria-label="Permalink to &quot;Prepare work on the host&quot;">​</a></h2><p>Mention and DM handlers may return a prepared <code>message</code>, <code>workspaceFiles</code>, or <code>cloud</code> block. It&#39;s the same host-prep pattern as <a href="./webhooks.html#prepare-on-the-host-then-hand-off">custom channels</a>. PR agents use it: extract a PR URL from the mention text and run the same host path as the HTTP channel.</p><p>Slack file uploads are attached automatically. Images become vision input. Supported documents become workspace files for the turn.</p><h2 id="add-approval-buttons" tabindex="-1">Add approval buttons <a class="header-anchor" href="#add-approval-buttons" aria-label="Permalink to &quot;Add approval buttons&quot;">​</a></h2><p>Tools with <code>needsApproval</code> park until a person decides. Route that through Slack with one flag:</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;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> default</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> slackChannel</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
36
36
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> toolApprovals: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">true</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// posts Block Kit Approve/Deny cards + routes clicks</span></span>
37
37
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span></code></pre></div><p>Approval cards need interactivity on the Slack app. Recreate with <code>slack create</code> if clicks do nothing. Composing events by hand: spread <code>buildToolApprovalEvents({ credentials })</code> into <code>events</code> and set <code>interactivity: true</code> on the channel so Socket Mode routes the clicks.</p><p>Approval buttons need Socket Mode. <code>slackChannel({ cursorAccount: true })</code> rejects <code>toolApprovals</code> and <code>interactivity</code> at construction, since the Cursor Slack connection does not relay Block Kit clicks. Use a dedicated Slack app to run approvals for a cursor-account agent.</p><p>Cards show redacted, truncated arguments (Block Kit size limits); execution still uses the full validated input, so review sensitive tools in the playground when the arguments may exceed the card. Approvals exist for <code>execution: &quot;server&quot;</code> tools on the local runtime only, and parked calls do not survive a host restart. The full lifecycle is in <a href="./human-in-the-loop.html">Human-in-the-loop</a>.</p><h2 id="run-several-agents-on-one-host" tabindex="-1">Run several agents on one host <a class="header-anchor" href="#run-several-agents-on-one-host" aria-label="Permalink to &quot;Run several agents on one host&quot;">​</a></h2><p>One Slack app and token pair per agent. Never share a pair across agents in the same process. <code>envPrefix</code> keeps them apart (<code>WEATHER_AGENT_SLACK_*</code>, <code>TRIAGE_SLACK_*</code>, …), and agents without tokens mount with their Slack channel idle while everything else serves normally.</p><h2 id="keep-the-channel-healthy" tabindex="-1">Keep the channel healthy <a class="header-anchor" href="#keep-the-channel-healthy" aria-label="Permalink to &quot;Keep the channel healthy&quot;">​</a></h2><p>Two habits matter most.</p><ul><li>Don&#39;t <code>await</code> long work inside Slack dispatch handlers. The pack dispatches through <code>waitUntil</code> and streams as the turn progresses.</li><li>In <code>--dev</code> (loopback) or <code>--allow-anonymous</code> (trusted shared host), the playground can list and stream Slack sessions and resolve their parked approvals (the audit trail records the HTTP caller). Bearer-auth hosts stay strict: Slack approvals must come from Slack interactivity or a matching principal.</li></ul><h2 id="cli-reference" tabindex="-1">CLI reference <a class="header-anchor" href="#cli-reference" aria-label="Permalink to &quot;CLI reference&quot;">​</a></h2><p>The <code>slack</code> subcommands cover setup end to end.</p><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;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> slack</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> setup</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # two-product chooser plus manual phases</span></span>
38
38
  <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> slack</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> create</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --dir</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> .</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # dashboard wizard (dev app)</span></span>
@@ -41,4 +41,4 @@ import{_ as a,c as e,o as i,ag as t}from"./chunks/framework.CAZyNGu9.js";const c
41
41
  <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> slack</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> icon</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> ./icon.png</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --dir</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> .</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # set the provisioned app&#39;s icon</span></span>
42
42
  <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> slack</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> init</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --manual</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --dir</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> .</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # manifests to paste at api.slack.com</span></span>
43
43
  <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> slack</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> manifest</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --env</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> both</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # regenerate those JSON files</span></span>
44
- <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> slack</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> doctor</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --prefix</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> MY_AGENT</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # token / connectivity checks</span></span></code></pre></div><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="./human-in-the-loop.html">Human-in-the-loop</a>: the approval lifecycle behind <code>toolApprovals</code></li><li><a href="./webhooks.html">Webhooks and custom channels</a>: the mechanism this pack is built on</li></ul>`,72)])])}const g=a(n,[["render",h]]);export{c as __pageData,g as default};
44
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> slack</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> doctor</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --prefix</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> MY_AGENT</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # token / connectivity checks</span></span></code></pre></div><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="./human-in-the-loop.html">Human-in-the-loop</a>: the approval lifecycle behind <code>toolApprovals</code></li><li><a href="./webhooks.html">Webhooks and custom channels</a>: the mechanism this pack is built on</li></ul>`,74)])])}const g=a(n,[["render",h]]);export{c as __pageData,g as default};
@@ -1 +1 @@
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: Cursor-hosted connection, a dedicated Socket Mode app via the dashboard wizard, or a manual manifest import.","frontmatter":{"title":"Slack","description":"Put the agent in Slack: Cursor-hosted connection, a dedicated Socket Mode app via the dashboard wizard, or a manual manifest import."},"headers":[],"relativePath":"guides/slack.md","filePath":"guides/slack.md"}'),n={name:"guides/slack.md"};function h(o,s,l,p,r,d){return i(),e("div",null,[...s[0]||(s[0]=[t("",72)])])}const g=a(n,[["render",h]]);export{c as __pageData,g as default};
1
+ import{_ as a,c as e,o as i,ag as t}from"./chunks/framework.BCISBCiQ.js";const c=JSON.parse('{"title":"Slack","description":"Put the agent in Slack: Cursor-hosted connection, a dedicated Socket Mode app via the dashboard wizard, or a manual manifest import.","frontmatter":{"title":"Slack","description":"Put the agent in Slack: Cursor-hosted connection, a dedicated Socket Mode app via the dashboard wizard, or a manual manifest import."},"headers":[],"relativePath":"guides/slack.md","filePath":"guides/slack.md"}'),n={name:"guides/slack.md"};function h(o,s,l,p,r,d){return i(),e("div",null,[...s[0]||(s[0]=[t("",74)])])}const g=a(n,[["render",h]]);export{c as __pageData,g as default};
@@ -1,4 +1,4 @@
1
- import{_ as i,c as a,o as n,ag as h}from"./chunks/framework.CAZyNGu9.js";const o=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 e(k,s,l,p,r,E){return n(),a("div",null,[...s[0]||(s[0]=[h(`<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>
1
+ import{_ as i,c as a,o as n,ag as h}from"./chunks/framework.BCISBCiQ.js";const o=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 e(k,s,l,p,r,E){return n(),a("div",null,[...s[0]||(s[0]=[h(`<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
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
3
  <span class="line"></span>
4
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>
@@ -47,11 +47,11 @@ import{_ as i,c as a,o as n,ag as h}from"./chunks/framework.CAZyNGu9.js";const o
47
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
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
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="hosted-aliases-need-an-alias-token-relay" tabindex="-1">Hosted aliases need an alias-token relay <a class="header-anchor" href="#hosted-aliases-need-an-alias-token-relay" aria-label="Permalink to &quot;Hosted aliases need an alias-token relay&quot;">​</a></h2><p>Cursor-managed deployments expose a stable alias URL. External callers must send <code>X-Agent-Alias-Token</code> on every request to that URL. Channel auth still runs after the alias gate.</p><p>Webhook providers that cannot attach custom headers cannot POST straight at a managed alias. Put a relay (or other authenticating intermediary) in front, use a Cursor-managed ingress path that does not use the public alias (for example Cursor Slack / GitHub event relay), or self-host. See <a href="./../deployment.html#use-the-hosted-agent">Deployment</a>.</p><h2 id="example-linear-as-the-control-plane" tabindex="-1">Example: Linear as the control plane <a class="header-anchor" href="#example-linear-as-the-control-plane" aria-label="Permalink to &quot;Example: Linear as the control plane&quot;">​</a></h2><p>Everything above composes into a working ticket-driven agent. This example wires Linear to the agent: new issues and comments start or resume sessions, and replies land back on the issue as comments. The same shape works for any tracker with signed webhooks.</p><p>Create the webhook in Linear under Settings → API → &quot;New webhook&quot;, pointed at <code>https://&lt;your-host&gt;/&lt;slug&gt;/v1/channels/linear</code>, and copy the signing secret. Linear requires a public HTTPS URL, so use a tunnel during local development or test with signed fixtures (below). Set three environment variables:</p><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:#24292E;--shiki-dark:#E1E4E8;">LINEAR_WEBHOOK_SECRET</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">lin_wh_...</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # the webhook&#39;s signing secret</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 <code>publicEndpoint()</code>. Any <code>(request, info) =&gt; AuthContext | null</code> function composes with them.</p><p>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="receive-signed-webhooks-on-managed-hosting" tabindex="-1">Receive signed webhooks on managed hosting <a class="header-anchor" href="#receive-signed-webhooks-on-managed-hosting" aria-label="Permalink to &quot;Receive signed webhooks on managed hosting&quot;">​</a></h2><p>Cursor-managed deployments expose a stable alias URL. External callers normally send <code>X-Agent-Alias-Token</code> on every request. Webhook providers often cannot set it.</p><p>Add <code>publicEndpoint()</code> to a custom channel that verifies its own provider signature. Only that channel path skips the alias token. Session and tool routes stay private. See <a href="./../deployment.html#use-the-hosted-agent">Deployment</a>.</p><h2 id="example-linear-as-the-control-plane" tabindex="-1">Example: Linear as the control plane <a class="header-anchor" href="#example-linear-as-the-control-plane" aria-label="Permalink to &quot;Example: Linear as the control plane&quot;">​</a></h2><p>Everything above composes into a working ticket-driven agent. This example wires Linear to the agent: new issues and comments start or resume sessions, and replies land back on the issue as comments. The same shape works for any tracker with signed webhooks.</p><p>Create the webhook in Linear under Settings → API → &quot;New webhook&quot;, pointed at <code>https://&lt;your-host&gt;/&lt;slug&gt;/v1/channels/linear</code>, and copy the signing secret. Linear requires a public HTTPS URL, so use a tunnel during local development or test with signed fixtures (below). Set three environment variables:</p><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:#24292E;--shiki-dark:#E1E4E8;">LINEAR_WEBHOOK_SECRET</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">lin_wh_...</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # the webhook&#39;s signing secret</span></span>
51
51
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">LINEAR_API_KEY</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">lin_api_...</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # posts replies as comments</span></span>
52
52
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">LINEAR_AGENT_USER_ID</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">...</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # the API key&#39;s user: query { viewer { id } }</span></span></code></pre></div><p><code>LINEAR_AGENT_USER_ID</code> matters: replies posted with the API key trigger the Comment webhook again, so the channel must recognize and skip its own comments. Without the guard, every reply starts another turn.</p><p>Author <code>agent/channels/linear.ts</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;"> { Buffer } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &quot;node:buffer&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
53
53
  <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { createHmac, timingSafeEqual } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &quot;node:crypto&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
54
- <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { allowAll, 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>
54
+ <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { defineChannel, POST, publicEndpoint } </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>
55
55
  <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>
56
56
  <span class="line"></span>
57
57
  <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> secret</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> process.env.</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">LINEAR_WEBHOOK_SECRET</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>
@@ -108,8 +108,7 @@ import{_ as i,c as a,o as n,ag as h}from"./chunks/framework.CAZyNGu9.js";const o
108
108
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span>
109
109
  <span class="line"></span>
110
110
  <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>
111
- <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // The HMAC check is the request auth, so admit everything at the route.</span></span>
112
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> auth: [</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">allowAll</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">()],</span></span>
111
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> auth: [</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">publicEndpoint</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">()],</span></span>
113
112
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> routes: [</span></span>
114
113
  <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;/&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, {</span></span>
115
114
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> description: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;Linear webhook ingress&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
@@ -223,4 +222,4 @@ import{_ as i,c as a,o as n,ag as h}from"./chunks/framework.CAZyNGu9.js";const o
223
222
  <span class="line"><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> .update(fs.readFileSync(&quot;fixtures/issue-create.json&quot;)).digest(&quot;hex&quot;))&#39;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">)</span></span>
224
223
  <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/linear/</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> \\</span></span>
225
224
  <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;"> -H</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &quot;linear-signature: </span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">$SIG</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> \\</span></span>
226
- <span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --data-binary</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> @fixtures/issue-create.json</span></span></code></pre></div><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>agent-sdk 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>`,59)])])}const g=i(t,[["render",e]]);export{o as __pageData,g as default};
225
+ <span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --data-binary</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> @fixtures/issue-create.json</span></span></code></pre></div><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>agent-sdk 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>`,60)])])}const g=i(t,[["render",e]]);export{o as __pageData,g as default};
@@ -1 +1 @@
1
- import{_ as i,c as a,o as n,ag as h}from"./chunks/framework.CAZyNGu9.js";const o=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 e(k,s,l,p,r,E){return n(),a("div",null,[...s[0]||(s[0]=[h("",59)])])}const g=i(t,[["render",e]]);export{o as __pageData,g as default};
1
+ import{_ as i,c as a,o as n,ag as h}from"./chunks/framework.BCISBCiQ.js";const o=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 e(k,s,l,p,r,E){return n(),a("div",null,[...s[0]||(s[0]=[h("",60)])])}const g=i(t,[["render",e]]);export{o as __pageData,g as default};
@@ -1,4 +1,4 @@
1
- import{_ as t,c as i,o as a,ag as l}from"./chunks/framework.CAZyNGu9.js";const m=JSON.parse('{"title":"Hillclimbing","description":"Improve an agent one measured round at a time, with the hillclimb skill running the loop with you.","frontmatter":{"title":"Hillclimbing","description":"Improve an agent one measured round at a time, with the hillclimb skill running the loop with you."},"headers":[],"relativePath":"hillclimbing.md","filePath":"hillclimbing.md"}'),o={name:"hillclimbing.md"};function n(r,e,s,h,d,c){return a(),i("div",null,[...e[0]||(e[0]=[l(`<h1 id="hillclimbing" tabindex="-1">Hillclimbing <a class="header-anchor" href="#hillclimbing" aria-label="Permalink to &quot;Hillclimbing&quot;">​</a></h1><p>Make an agent better on fixed inputs: measure, change one lever, remeasure, and lock every kept win with an eval.</p><h2 id="what-is-hillclimbing" tabindex="-1">What is hillclimbing? <a class="header-anchor" href="#what-is-hillclimbing" aria-label="Permalink to &quot;What is hillclimbing?&quot;">​</a></h2><p>Hillclimbing is a measured improvement loop. You pin a few fixtures, name the one dominant problem in the run, change one lever, and check the same fixtures again. Keep only what helps. Every kept change lands an <a href="./evals.html">eval</a> so the win stays put.</p><p>You don&#39;t have to run the loop alone. The package ships a coding-agent skill that drives it with you.</p><div class="language-mermaid vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">mermaid</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">flowchart LR</span></span>
1
+ import{_ as t,c as i,o as a,ag as l}from"./chunks/framework.BCISBCiQ.js";const m=JSON.parse('{"title":"Hillclimbing","description":"Improve an agent one measured round at a time, with the hillclimb skill running the loop with you.","frontmatter":{"title":"Hillclimbing","description":"Improve an agent one measured round at a time, with the hillclimb skill running the loop with you."},"headers":[],"relativePath":"hillclimbing.md","filePath":"hillclimbing.md"}'),o={name:"hillclimbing.md"};function n(r,e,s,h,d,c){return a(),i("div",null,[...e[0]||(e[0]=[l(`<h1 id="hillclimbing" tabindex="-1">Hillclimbing <a class="header-anchor" href="#hillclimbing" aria-label="Permalink to &quot;Hillclimbing&quot;">​</a></h1><p>Make an agent better on fixed inputs: measure, change one lever, remeasure, and lock every kept win with an eval.</p><h2 id="what-is-hillclimbing" tabindex="-1">What is hillclimbing? <a class="header-anchor" href="#what-is-hillclimbing" aria-label="Permalink to &quot;What is hillclimbing?&quot;">​</a></h2><p>Hillclimbing is a measured improvement loop. You pin a few fixtures, name the one dominant problem in the run, change one lever, and check the same fixtures again. Keep only what helps. Every kept change lands an <a href="./evals.html">eval</a> so the win stays put.</p><p>You don&#39;t have to run the loop alone. The package ships a coding-agent skill that drives it with you.</p><div class="language-mermaid vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">mermaid</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">flowchart LR</span></span>
2
2
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> measure[Measure] --&gt; change[Change one lever]</span></span>
3
3
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> change --&gt; remeasure[Remeasure]</span></span>
4
4
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> remeasure --&gt; measure</span></span></code></pre></div><h2 id="how-do-i-hillclimb-an-agent-with-a-coding-agent" tabindex="-1">How do I hillclimb an agent with a coding agent? <a class="header-anchor" href="#how-do-i-hillclimb-an-agent-with-a-coding-agent" aria-label="Permalink to &quot;How do I hillclimb an agent with a coding agent?&quot;">​</a></h2><p>Have Cursor read <a href="./../skills/hillclimb/SKILL.html"><code>skills/hillclimb/SKILL.md</code></a>.</p><p>Tell it:</p><ol><li><strong>Which agent</strong> you&#39;re improving (path or slug)</li><li><strong>One to three fixtures</strong> you&#39;ll reuse every round: a PR URL, a saved webhook body, or a canonical chat prompt</li><li><strong>What &quot;better&quot; means</strong> this round: correct tool choice, fewer tools, lower latency, or output quality. Name the freeze line too: API shape, public output, and existing evals that must stay green</li></ol><p>The skill serves the agent, hits your fixtures, reads the session trajectory, proposes one change, remeasures, and checks with you before the next round.</p><p>Other skills cover the edges:</p><table tabindex="0"><thead><tr><th>When you need…</th><th>Skill</th></tr></thead><tbody><tr><td>The measured improvement loop</td><td><a href="./../skills/hillclimb/SKILL.html"><code>skills/hillclimb/SKILL.md</code></a></td></tr><tr><td>An eval that locks a kept win</td><td><a href="./../skills/evals/SKILL.html"><code>skills/evals/SKILL.md</code></a></td></tr><tr><td>Repeatable GitHub webhook inputs</td><td><a href="./../skills/github/SKILL.html"><code>skills/github/SKILL.md</code></a></td></tr><tr><td>A run that misbehaves</td><td><a href="./../skills/debug/SKILL.html"><code>skills/debug/SKILL.md</code></a></td></tr></tbody></table><p>See <a href="./building-with-agents.html">Building agents with agents</a> for every framework skill and a good first prompt.</p><h2 id="what-do-i-need-before-a-hillclimb-round" tabindex="-1">What do I need before a hillclimb round? <a class="header-anchor" href="#what-do-i-need-before-a-hillclimb-round" aria-label="Permalink to &quot;What do I need before a hillclimb round?&quot;">​</a></h2><p>Agree on four things before you edit:</p><ol><li><strong>The target agent</strong>: the project you&#39;re improving</li><li><strong>Fixtures</strong>: one to three fixed inputs you can compare across runs</li><li><strong>Success criteria</strong>: what better means this round</li><li><strong>The freeze line</strong>: what must not change</li></ol><p>Pin the input first. A moving fixture is noise. For GitHub agents, use <code>agent-sdk github replay</code> (see the <a href="./guides/github.html">GitHub guide</a>). For a single tool without a model turn, use <code>agent-sdk call</code>. For a chat turn, use <code>agent-sdk run --dir . --message &quot;…&quot;</code>.</p><h2 id="how-do-i-run-one-hillclimb-round" tabindex="-1">How do I run one hillclimb round? <a class="header-anchor" href="#how-do-i-run-one-hillclimb-round" aria-label="Permalink to &quot;How do I run one hillclimb round?&quot;">​</a></h2><p><strong>Measure.</strong> Hit the agent the way a user would: playground, channel HTTP, or Slack in <code>--dev</code>. Or ask the hillclimb skill to do it. <code>agent-sdk run</code> returns a JSON trajectory and writes a trace under <code>.agent-serve/traces/</code>.</p><p><strong>Reflect.</strong> Score the trajectory, not impressions. Was the answer right? Did the model thrash (too many tools, fat evidence, grep loops)? Did it invent work the host should have prepared? Name the single dominant problem for this round in one sentence. Example: &quot;Full-file dumps trigger grep loops.&quot;</p><p><strong>Change one lever.</strong> Prefer the smallest change that addresses that problem:</p><ol><li>Host prep: seed what the model needs so it doesn&#39;t hunt</li><li>Evidence shape: trim or reorder artifacts</li><li>Instructions and skills: tighten the procedure</li><li>Tool surface: remove or gate tools that invite wandering</li><li>Framework changes: only when the agent can&#39;t express the fix</li></ol><p><strong>Remeasure.</strong> Same fixtures. Diff tools, wall time, and quality side by side. Keep the change only if the target metric improves and the freeze line holds.</p><h2 id="how-do-i-lock-a-hillclimb-improvement-with-an-eval" tabindex="-1">How do I lock a hillclimb improvement with an eval? <a class="header-anchor" href="#how-do-i-lock-a-hillclimb-improvement-with-an-eval" aria-label="Permalink to &quot;How do I lock a hillclimb improvement with an eval?&quot;">​</a></h2><p>Every kept change needs an eval that would have failed before the change: a tool-choice gate, an <code>action.result</code> count bound, or an output-shape check. Run <code>agent-sdk eval --dir . --json</code> between rounds. Never weaken an existing gate to pass the round.</p><p>Details live in <a href="./evals.html">Evals</a>. The evals skill will author the case with you.</p><h2 id="what-habits-help-hillclimbing-stay-reliable" tabindex="-1">What habits help hillclimbing stay reliable? <a class="header-anchor" href="#what-habits-help-hillclimbing-stay-reliable" aria-label="Permalink to &quot;What habits help hillclimbing stay reliable?&quot;">​</a></h2><ul><li>One problem per round. Don&#39;t bundle &quot;trim evidence and rewrite instructions&quot; unless you chose that on purpose.</li><li>Keep fixtures fixed until you deliberately need a harder case.</li><li>Separate host work from model tools when you blame latency. Moving deterministic prep onto the host is often the biggest win. In one PR reviewer, host-prepared evidence cut turns from about 8 minutes to about 1 minute.</li><li>Spot-check quality on at least one fixture against a known-good answer. Efficiency-only climbs quietly drop findings.</li><li>Treat <code>turn.failed</code> with <code>&quot;turn interrupted&quot;</code> as expected when a follow-up or stop preempted the turn.</li><li>Don&#39;t deploy, post to real surfaces, or weaken evals as part of a climb.</li></ul><h2 id="related" tabindex="-1">Related <a class="header-anchor" href="#related" aria-label="Permalink to &quot;Related&quot;">​</a></h2><ul><li><a href="./evals.html">Evals</a></li><li><a href="./building-with-agents.html">Building agents with agents</a></li><li><a href="./guides/github.html">GitHub guide</a></li><li><a href="./troubleshooting.html">Fix common agent problems</a></li></ul>`,31)])])}const p=t(o,[["render",n]]);export{m as __pageData,p as default};
@@ -1 +1 @@
1
- import{_ as t,c as i,o as a,ag as l}from"./chunks/framework.CAZyNGu9.js";const m=JSON.parse('{"title":"Hillclimbing","description":"Improve an agent one measured round at a time, with the hillclimb skill running the loop with you.","frontmatter":{"title":"Hillclimbing","description":"Improve an agent one measured round at a time, with the hillclimb skill running the loop with you."},"headers":[],"relativePath":"hillclimbing.md","filePath":"hillclimbing.md"}'),o={name:"hillclimbing.md"};function n(r,e,s,h,d,c){return a(),i("div",null,[...e[0]||(e[0]=[l("",31)])])}const p=t(o,[["render",n]]);export{m as __pageData,p as default};
1
+ import{_ as t,c as i,o as a,ag as l}from"./chunks/framework.BCISBCiQ.js";const m=JSON.parse('{"title":"Hillclimbing","description":"Improve an agent one measured round at a time, with the hillclimb skill running the loop with you.","frontmatter":{"title":"Hillclimbing","description":"Improve an agent one measured round at a time, with the hillclimb skill running the loop with you."},"headers":[],"relativePath":"hillclimbing.md","filePath":"hillclimbing.md"}'),o={name:"hillclimbing.md"};function n(r,e,s,h,d,c){return a(),i("div",null,[...e[0]||(e[0]=[l("",31)])])}const p=t(o,[["render",n]]);export{m as __pageData,p as default};
@@ -0,0 +1,5 @@
1
+ import{_ as t,c as a,o as s,ag as i}from"./chunks/framework.BCISBCiQ.js";const g=JSON.parse('{"title":"Agent SDK documentation","description":"Build and run Cursor agents with tools, approvals, channels, and evals.","frontmatter":{"title":"Agent SDK documentation","description":"Build and run Cursor agents with tools, approvals, channels, and evals."},"headers":[],"relativePath":"index.md","filePath":"README.md"}'),n={name:"index.md"};function r(l,e,o,h,d,c){return s(),a("div",null,[...e[0]||(e[0]=[i(`<h1 id="agent-sdk-documentation" tabindex="-1">Agent SDK documentation <a class="header-anchor" href="#agent-sdk-documentation" aria-label="Permalink to &quot;Agent SDK documentation&quot;">​</a></h1><p>Use the Agent SDK to define Cursor agents in TypeScript and Markdown. See <a href="./reference/project-layout.html">Project layout</a> for the directory structure.</p><p>Use Node 22.13 or newer. Bun isn&#39;t supported.</p><p>Create a project:</p><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;">npx</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> @cursor/july</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> init</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> ./my-agent</span></span>
2
+ <span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">cd</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> my-agent</span></span>
3
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> dev</span></span></code></pre></div><p>If <code>agent-sdk</code> isn&#39;t on <code>PATH</code>, use <code>npx @cursor/july &lt;command&gt;</code>.</p><p>Open the docs locally:</p><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;">npx</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> @cursor/july</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> docs</span></span></code></pre></div><h2 id="where-to-start" tabindex="-1">Where to start <a class="header-anchor" href="#where-to-start" aria-label="Permalink to &quot;Where to start&quot;">​</a></h2><table tabindex="0"><thead><tr><th>You are...</th><th>Start with</th></tr></thead><tbody><tr><td>New to the Agent SDK</td><td><a href="./quickstart.html">Quickstart</a> (PR reviewer), then <a href="./concepts.html">Concepts</a></td></tr><tr><td>Building a new agent with Cursor</td><td><a href="./scaffolding-agents.html">Scaffold an agent with Cursor</a></td></tr><tr><td>Turning a Cursor Automation into a project</td><td><a href="./guides/convert-automation.html">Convert a Cursor Automation</a></td></tr><tr><td>Learning from working agents</td><td><a href="./example-agents/">Example agents</a></td></tr><tr><td>Wiring an agent to Slack</td><td><a href="./guides/slack.html">Slack guide</a></td></tr><tr><td>Starting from a packaged template</td><td><a href="./templates/demo.html">Demo</a>, <a href="./templates/security-reviewer.html">Security reviewer</a>, <a href="./templates/triage.html">Triage</a>, or <a href="./templates/agentic-owners.html">Agentic Owners</a></td></tr><tr><td>Wiring an agent to GitHub webhooks</td><td><a href="./guides/github.html">GitHub guide</a></td></tr><tr><td>Driving PRs from a cloud VM</td><td><a href="./templates/pr-autofixer.html">PR autofixer template</a></td></tr><tr><td>Driving an agent from Linear (or another tracker)</td><td><a href="./guides/webhooks.html#example-linear-as-the-control-plane">Webhooks guide: Linear example</a></td></tr><tr><td>Making an existing agent measurably better</td><td><a href="./evals.html">Evals</a>, then <a href="./hillclimbing.html">Hillclimbing</a></td></tr><tr><td>Comparing variants on live traffic</td><td><a href="./ab.html">Live A/B metrics</a></td></tr><tr><td>Deploying with Cursor or on your own infrastructure</td><td><a href="./deployment.html">Deployment</a></td></tr><tr><td>Debugging something that misbehaves</td><td><a href="./troubleshooting.html">Fix common agent problems</a></td></tr></tbody></table><h2 id="documentation" tabindex="-1">Documentation <a class="header-anchor" href="#documentation" aria-label="Permalink to &quot;Documentation&quot;">​</a></h2><p><strong>Core</strong></p><ul><li><a href="./quickstart.html">Quickstart</a>: build a PR reviewer that classifies changes by complexity and handles GitHub webhook events.</li><li><a href="./scaffolding-agents.html">Scaffold an agent with Cursor</a>: use the bundled skill for a guided build.</li><li><a href="./guides/convert-automation.html">Convert a Cursor Automation</a>: export a dashboard Automation into an Agent SDK project.</li><li><a href="./concepts.html">Concepts</a>: agent discovery, sessions, channels, runtimes, and observability.</li></ul><p><strong>Templates</strong></p><ul><li><a href="./templates/demo.html">Record a walkthrough from a collected PR</a>: host collects the PR, the model records, then comments.</li><li><a href="./templates/security-reviewer.html">Security reviewer</a>: review pull requests for exploitable bugs and post one comment.</li><li><a href="./templates/triage.html">Triage Linear or Jira issues in place</a>: classify existing tickets and comment on them.</li><li><a href="./templates/agentic-owners.html">Review pull requests with owners policies</a>: request owners and approve changes allowed by repository policy.</li><li><a href="./templates/pr-autofixer.html">Fix pull requests on a Cursor cloud VM</a></li></ul><p><strong>Self-improving Agents</strong></p><ul><li><a href="./building-with-agents.html">Building agents with agents</a>: use a coding agent to scaffold, run, and iterate on your agent.</li><li><a href="./evals.html">Evals</a>: author <code>defineEval</code> cases, pick fixtures, and use evals as regression checks.</li><li><a href="./ab.html">Live A/B metrics</a>: assign sticky variants and compare cumulative metrics on live sessions.</li><li><a href="./storage.html">Storage</a>: point durable storage at a backend you own with <code>defineStorage</code>.</li><li><a href="./hillclimbing.html">Hillclimbing</a>: measure and improve an agent iteratively.</li></ul><p><strong>Guides</strong></p><ul><li><a href="./guides/webhooks.html">Webhooks and custom channels</a>: give the agent its own HTTP surface.</li><li><a href="./guides/github.html">GitHub</a>: trigger the agent from pull requests, CI, and comments.</li><li><a href="./guides/slack.html">Slack</a>: put the agent in Slack over Socket Mode.</li><li><a href="./guides/human-in-the-loop.html">Human-in-the-loop approvals</a>: park a tool call until a person signs off.</li><li><a href="./guides/mcp-oauth.html">Host MCP OAuth</a>: authorize <code>oauth: true</code> connections, store tokens locally, and <code>--store</code> them on hosted deployments.</li><li><a href="./guides/agent-to-agent.html">Agent-to-agent</a>: every agent is an MCP server; agents can delegate to each other.</li><li><a href="./guides/cloud-runtime.html">Cloud runtime</a>: run turns on Cursor cloud agents instead of the local harness.</li><li><a href="./guides/opentelemetry.html">OpenTelemetry</a>: push session, turn, and tool traces to an OTLP collector you run.</li></ul><p><strong>Example agents</strong></p><ul><li><a href="./example-agents/">Choose the right example</a>: compare all twelve agents by runtime, channels, tools, state, and architecture.</li><li><a href="./example-agents/weather-agent.html">Weather agent</a>: explore tools, MCP, approvals, skills, subagents, schedules, hooks, A/B metrics, and evals.</li><li><a href="./example-agents/slack-agent.html">Slack agent</a>: put a minimal agent in Slack through an account-linked transport.</li><li><a href="./example-agents/concierge.html">Concierge</a>: delegate work to a peer agent with its own context and sessions.</li><li><a href="./example-agents/benny.html">Playbook router</a>: route Slack intake through inherited repository playbooks.</li><li><a href="./example-agents/oncall.html">Alert investigator</a>: watch a Slack alerts channel and pin a self-rechecking investigation to every alert thread.</li><li><a href="./example-agents/bugbot.html">PR evidence reviewer</a>: review a host-prepared, diff-first pull-request evidence tree.</li><li><a href="./example-agents/approval-buddy.html">Approval Buddy</a>: keep approval policy in code while subagents supply review findings.</li><li><a href="./example-agents/security-reviewer.html">Security Reviewer</a>: run a staged, parallel security pipeline with live playground progress.</li><li><a href="./example-agents/fsd.html">Remote PR coordinator</a>: hand PR triage from local chat and webhooks to durable remote sessions.</li><li><a href="./example-agents/knowledge-base.html">Knowledge base</a>: turn conversations about people, systems, decisions, and preferences into shared markdown.</li><li><a href="./example-agents/codebase-wiki.html">Codebase wiki</a>: ingest merged PRs into per-feature pages with a daily digest schedule.</li><li><a href="./example-agents/codeowners-review.html">Codeowners review</a>: route PR reviews by ownership to per-area playbooks and aggregate verdicts.</li></ul><p><strong>Operating</strong></p><ul><li><a href="./deployment.html">Deployment</a>: Cursor-managed hosting, self-hosting, auth, state, and operations.</li><li><a href="./troubleshooting.html">Fix common agent problems</a>: diagnose common failures by symptom.</li></ul><p><strong>Reference</strong></p><ul><li><a href="./reference/project-layout.html">Project layout</a>: the full folder structure.</li><li><a href="./reference/agent-config.html">Agent config</a> · <a href="./reference/instructions.html">Instructions</a> · <a href="./reference/tools.html">Tools</a> · <a href="./reference/prompt.html"><code>prompt</code></a> · <a href="./reference/skills.html">Skills</a> · <a href="./reference/connections.html">MCP connections</a> · <a href="./reference/subagents.html">Subagents</a></li><li><a href="./reference/channels.html">Channels</a> · <a href="./reference/schedules.html">Schedules and reminders</a> · <a href="./reference/hooks.html">Hooks</a> · <a href="./reference/sessions.html">Sessions and streaming</a> · <a href="./reference/playground.html">Playground</a></li><li><a href="./reference/cli.html">CLI</a> · <a href="./reference/http-api.html">HTTP API</a></li></ul><h2 id="run-the-cli" tabindex="-1">Run the CLI <a class="header-anchor" href="#run-the-cli" aria-label="Permalink to &quot;Run the CLI&quot;">​</a></h2><p>Docs use <code>agent-sdk &lt;command&gt;</code>. If it isn&#39;t on <code>PATH</code>, use <code>npx @cursor/july &lt;command&gt;</code>.</p><p>From <code>packages/agent-serve</code> in a source checkout:</p><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:#D73A49;--shiki-dark:#F97583;">alias</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> agent-sdk</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;pnpm exec tsx </span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">$PWD</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">/src/bin/agent-serve.ts&quot;</span></span></code></pre></div><h2 id="credentials" tabindex="-1">Credentials <a class="header-anchor" href="#credentials" aria-label="Permalink to &quot;Credentials&quot;">​</a></h2><p>Sign in to Cursor or set <code>CURSOR_API_KEY</code>:</p><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;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> login</span></span>
4
+ <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"># or: export CURSOR_API_KEY=key_...</span></span>
5
+ <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> whoami</span></span></code></pre></div><p>Confirm <code>agent-sdk whoami</code> shows the expected account.</p><h2 id="related-documentation" tabindex="-1">Related documentation <a class="header-anchor" href="#related-documentation" aria-label="Permalink to &quot;Related documentation&quot;">​</a></h2><ul><li>Package reference: <a href="./../README.html"><code>README.md</code></a></li><li>Coding-agent workflows: <a href="./../skills/"><code>skills/</code></a></li></ul>`,35)])])}const u=t(n,[["render",r]]);export{g as __pageData,u as default};
@@ -1 +1 @@
1
- import{_ as t,c as a,o as s,ag as i}from"./chunks/framework.CAZyNGu9.js";const u=JSON.parse('{"title":"Agent SDK documentation","description":"Build and run Cursor agents with tools, approvals, channels, and evals.","frontmatter":{"title":"Agent SDK documentation","description":"Build and run Cursor agents with tools, approvals, channels, and evals."},"headers":[],"relativePath":"index.md","filePath":"README.md"}'),n={name:"index.md"};function r(l,e,o,h,d,c){return s(),a("div",null,[...e[0]||(e[0]=[i("",35)])])}const g=t(n,[["render",r]]);export{u as __pageData,g as default};
1
+ import{_ as t,c as a,o as s,ag as i}from"./chunks/framework.BCISBCiQ.js";const g=JSON.parse('{"title":"Agent SDK documentation","description":"Build and run Cursor agents with tools, approvals, channels, and evals.","frontmatter":{"title":"Agent SDK documentation","description":"Build and run Cursor agents with tools, approvals, channels, and evals."},"headers":[],"relativePath":"index.md","filePath":"README.md"}'),n={name:"index.md"};function r(l,e,o,h,d,c){return s(),a("div",null,[...e[0]||(e[0]=[i("",35)])])}const u=t(n,[["render",r]]);export{g as __pageData,u as default};
@@ -1,4 +1,4 @@
1
- import{_ as i,c as a,o as n,ag as h}from"./chunks/framework.CAZyNGu9.js";const g=JSON.parse('{"title":"Build your first PR reviewer","description":"Create an agent that reviews pull requests by complexity, approves safe changes, and handles GitHub webhook events.","frontmatter":{"title":"Build your first PR reviewer","description":"Create an agent that reviews pull requests by complexity, approves safe changes, and handles GitHub webhook events."},"headers":[],"relativePath":"quickstart.md","filePath":"quickstart.md"}'),t={name:"quickstart.md"};function l(p,s,e,k,r,E){return n(),a("div",null,[...s[0]||(s[0]=[h(`<h1 id="build-your-first-pr-reviewer" tabindex="-1">Build your first PR reviewer <a class="header-anchor" href="#build-your-first-pr-reviewer" aria-label="Permalink to &quot;Build your first PR reviewer&quot;">​</a></h1><p>Build a GitHub PR reviewer that classifies changes as <code>trivial</code>, <code>moderate</code>, or <code>large</code>, then approves safe changes or requests human review. Add GitHub event handling so pull requests can trigger reviews.</p><h2 id="getting-started" tabindex="-1">Getting started <a class="header-anchor" href="#getting-started" aria-label="Permalink to &quot;Getting started&quot;">​</a></h2><ul><li><strong>Get started with an agent in Cursor:</strong> follow <a href="./scaffolding-agents.html">Scaffold an agent with Cursor</a> and ask Cursor to read <a href="./../skills/create-agent/SKILL.html"><code>skills/create-agent/SKILL.md</code></a>.</li><li><strong>Get started in the CLI:</strong> continue below.</li></ul><h2 id="prerequisites" tabindex="-1">Prerequisites <a class="header-anchor" href="#prerequisites" aria-label="Permalink to &quot;Prerequisites&quot;">​</a></h2><ul><li>Node 22.13 or newer. Bun isn&#39;t supported.</li><li>Run commands as <code>agent-sdk &lt;command&gt;</code>, or use <code>npx @cursor/july &lt;command&gt;</code> when the CLI isn&#39;t on <code>PATH</code>. See <a href="/docs/#run-the-cli">Run the CLI</a> for monorepo checkouts and other setups.</li><li>A Cursor credential for model turns. Sign in once:</li></ul><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;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> login</span></span></code></pre></div><p>You can also set <code>CURSOR_API_KEY</code> instead of signing in.</p><ul><li>Authenticate with <code>gh auth login</code> or <code>GITHUB_TOKEN</code>. You can read public pull requests. Posting reviews requires repository write access.</li></ul><h2 id="create-and-run-the-project" tabindex="-1">Create and run the project <a class="header-anchor" href="#create-and-run-the-project" aria-label="Permalink to &quot;Create and run the project&quot;">​</a></h2><p>Initialize the project and start the development server:</p><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;">npx</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> @cursor/july</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> init</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> ./sdk-pr-reviewer</span></span>
1
+ import{_ as i,c as a,o as n,ag as h}from"./chunks/framework.BCISBCiQ.js";const g=JSON.parse('{"title":"Build your first PR reviewer","description":"Create an agent that reviews pull requests by complexity, approves safe changes, and handles GitHub webhook events.","frontmatter":{"title":"Build your first PR reviewer","description":"Create an agent that reviews pull requests by complexity, approves safe changes, and handles GitHub webhook events."},"headers":[],"relativePath":"quickstart.md","filePath":"quickstart.md"}'),t={name:"quickstart.md"};function l(p,s,e,k,r,E){return n(),a("div",null,[...s[0]||(s[0]=[h(`<h1 id="build-your-first-pr-reviewer" tabindex="-1">Build your first PR reviewer <a class="header-anchor" href="#build-your-first-pr-reviewer" aria-label="Permalink to &quot;Build your first PR reviewer&quot;">​</a></h1><p>Build a GitHub PR reviewer that classifies changes as <code>trivial</code>, <code>moderate</code>, or <code>large</code>, then approves safe changes or requests human review. Add GitHub event handling so pull requests can trigger reviews.</p><h2 id="getting-started" tabindex="-1">Getting started <a class="header-anchor" href="#getting-started" aria-label="Permalink to &quot;Getting started&quot;">​</a></h2><ul><li><strong>Get started with an agent in Cursor:</strong> follow <a href="./scaffolding-agents.html">Scaffold an agent with Cursor</a> and ask Cursor to read <a href="./../skills/create-agent/SKILL.html"><code>skills/create-agent/SKILL.md</code></a>.</li><li><strong>Get started in the CLI:</strong> continue below.</li></ul><h2 id="prerequisites" tabindex="-1">Prerequisites <a class="header-anchor" href="#prerequisites" aria-label="Permalink to &quot;Prerequisites&quot;">​</a></h2><ul><li>Node 22.13 or newer. Bun isn&#39;t supported.</li><li>Run commands as <code>agent-sdk &lt;command&gt;</code>, or use <code>npx @cursor/july &lt;command&gt;</code> when the CLI isn&#39;t on <code>PATH</code>. See <a href="/docs/#run-the-cli">Run the CLI</a> for monorepo checkouts and other setups.</li><li>A Cursor credential for model turns. Sign in once:</li></ul><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;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> login</span></span></code></pre></div><p>You can also set <code>CURSOR_API_KEY</code> instead of signing in.</p><ul><li>Authenticate with <code>gh auth login</code> or <code>GITHUB_TOKEN</code>. You can read public pull requests. Posting reviews requires repository write access.</li></ul><h2 id="create-and-run-the-project" tabindex="-1">Create and run the project <a class="header-anchor" href="#create-and-run-the-project" aria-label="Permalink to &quot;Create and run the project&quot;">​</a></h2><p>Initialize the project and start the development server:</p><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;">npx</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> @cursor/july</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> init</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> ./sdk-pr-reviewer</span></span>
2
2
  <span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">cd</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> sdk-pr-reviewer</span></span>
3
3
  <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> dev</span></span></code></pre></div><p>Keep <code>agent-sdk dev</code> running. In a second terminal, run:</p><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;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> run</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --dir</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> .</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --message</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &quot;Introduce yourself in one sentence.&quot;</span></span></code></pre></div><p>Confirm the agent replies.</p><h2 id="add-review-instructions" tabindex="-1">Add review instructions <a class="header-anchor" href="#add-review-instructions" aria-label="Permalink to &quot;Add review instructions&quot;">​</a></h2><p>Replace <code>agent/instructions.md</code>:</p><div class="language-md vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">md</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#005CC5;--shiki-light-font-weight:bold;--shiki-dark:#79B8FF;--shiki-dark-font-weight:bold;"># PR reviewer</span></span>
4
4
  <span class="line"></span>
@@ -1 +1 @@
1
- import{_ as i,c as a,o as n,ag as h}from"./chunks/framework.CAZyNGu9.js";const g=JSON.parse('{"title":"Build your first PR reviewer","description":"Create an agent that reviews pull requests by complexity, approves safe changes, and handles GitHub webhook events.","frontmatter":{"title":"Build your first PR reviewer","description":"Create an agent that reviews pull requests by complexity, approves safe changes, and handles GitHub webhook events."},"headers":[],"relativePath":"quickstart.md","filePath":"quickstart.md"}'),t={name:"quickstart.md"};function l(p,s,e,k,r,E){return n(),a("div",null,[...s[0]||(s[0]=[h("",52)])])}const o=i(t,[["render",l]]);export{g as __pageData,o as default};
1
+ import{_ as i,c as a,o as n,ag as h}from"./chunks/framework.BCISBCiQ.js";const g=JSON.parse('{"title":"Build your first PR reviewer","description":"Create an agent that reviews pull requests by complexity, approves safe changes, and handles GitHub webhook events.","frontmatter":{"title":"Build your first PR reviewer","description":"Create an agent that reviews pull requests by complexity, approves safe changes, and handles GitHub webhook events."},"headers":[],"relativePath":"quickstart.md","filePath":"quickstart.md"}'),t={name:"quickstart.md"};function l(p,s,e,k,r,E){return n(),a("div",null,[...s[0]||(s[0]=[h("",52)])])}const o=i(t,[["render",l]]);export{g as __pageData,o as default};
@@ -1,4 +1,4 @@
1
- import{_ as e,c as t,o as i,ag as a}from"./chunks/framework.CAZyNGu9.js";const k=JSON.parse('{"title":"Agent config","description":"defineAgent at agent/agent.ts: the model, the local and cloud runtimes, and serving programmatically.","frontmatter":{"title":"Agent config","description":"defineAgent at agent/agent.ts: the model, the local and cloud runtimes, and serving programmatically."},"headers":[],"relativePath":"reference/agent-config.md","filePath":"reference/agent-config.md"}'),n={name:"reference/agent-config.md"};function o(l,s,d,r,h,c){return i(),t("div",null,[...s[0]||(s[0]=[a(`<h1 id="agent-config-agent-agent-ts" tabindex="-1">Agent config (<code>agent/agent.ts</code>) <a class="header-anchor" href="#agent-config-agent-agent-ts" aria-label="Permalink to &quot;Agent config (\`agent/agent.ts\`)&quot;">​</a></h1><p><code>agent/agent.ts</code> default-exports <code>defineAgent(config)</code>: which model runs the agent, where turns execute, and runtime-specific defaults. Everything is optional on the root agent.</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;"> { defineAgent } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &quot;@cursor/july&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
1
+ import{_ as e,c as t,o as i,ag as a}from"./chunks/framework.BCISBCiQ.js";const k=JSON.parse('{"title":"Agent config","description":"defineAgent at agent/agent.ts: the model, the local and cloud runtimes, and serving programmatically.","frontmatter":{"title":"Agent config","description":"defineAgent at agent/agent.ts: the model, the local and cloud runtimes, and serving programmatically."},"headers":[],"relativePath":"reference/agent-config.md","filePath":"reference/agent-config.md"}'),n={name:"reference/agent-config.md"};function o(l,s,d,r,h,c){return i(),t("div",null,[...s[0]||(s[0]=[a(`<h1 id="agent-config-agent-agent-ts" tabindex="-1">Agent config (<code>agent/agent.ts</code>) <a class="header-anchor" href="#agent-config-agent-agent-ts" aria-label="Permalink to &quot;Agent config (\`agent/agent.ts\`)&quot;">​</a></h1><p><code>agent/agent.ts</code> default-exports <code>defineAgent(config)</code>: which model runs the agent, where turns execute, and runtime-specific defaults. Everything is optional on the root agent.</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;"> { defineAgent } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &quot;@cursor/july&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
2
2
  <span class="line"></span>
3
3
  <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;"> defineAgent</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
4
4
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> model: {</span></span>
@@ -1 +1 @@
1
- import{_ as e,c as t,o as i,ag as a}from"./chunks/framework.CAZyNGu9.js";const k=JSON.parse('{"title":"Agent config","description":"defineAgent at agent/agent.ts: the model, the local and cloud runtimes, and serving programmatically.","frontmatter":{"title":"Agent config","description":"defineAgent at agent/agent.ts: the model, the local and cloud runtimes, and serving programmatically."},"headers":[],"relativePath":"reference/agent-config.md","filePath":"reference/agent-config.md"}'),n={name:"reference/agent-config.md"};function o(l,s,d,r,h,c){return i(),t("div",null,[...s[0]||(s[0]=[a("",50)])])}const u=e(n,[["render",o]]);export{k as __pageData,u as default};
1
+ import{_ as e,c as t,o as i,ag as a}from"./chunks/framework.BCISBCiQ.js";const k=JSON.parse('{"title":"Agent config","description":"defineAgent at agent/agent.ts: the model, the local and cloud runtimes, and serving programmatically.","frontmatter":{"title":"Agent config","description":"defineAgent at agent/agent.ts: the model, the local and cloud runtimes, and serving programmatically."},"headers":[],"relativePath":"reference/agent-config.md","filePath":"reference/agent-config.md"}'),n={name:"reference/agent-config.md"};function o(l,s,d,r,h,c){return i(),t("div",null,[...s[0]||(s[0]=[a("",50)])])}const u=e(n,[["render",o]]);export{k as __pageData,u as default};
@@ -1,4 +1,4 @@
1
- import{_ as a,c as e,o as i,ag as t}from"./chunks/framework.CAZyNGu9.js";const k=JSON.parse('{"title":"Artifacts","description":"Tag durable outputs (reviewed PRs, reports) so they persist across sessions, stream as events, and list over HTTP.","frontmatter":{"title":"Artifacts","description":"Tag durable outputs (reviewed PRs, reports) so they persist across sessions, stream as events, and list over HTTP."},"headers":[],"relativePath":"reference/artifacts.md","filePath":"reference/artifacts.md"}'),n={name:"reference/artifacts.md"};function d(o,s,r,l,h,p){return i(),e("div",null,[...s[0]||(s[0]=[t(`<h1 id="artifacts" tabindex="-1">Artifacts <a class="header-anchor" href="#artifacts" aria-label="Permalink to &quot;Artifacts&quot;">​</a></h1><p>An artifact marks a durable output the agent produced: a reviewed PR URL, a generated report, a decision record. Sessions come and go; artifacts persist across them, capped and listable, so the people supervising an agent see what it shipped without replaying event streams.</p><h2 id="declare-kinds" tabindex="-1">Declare kinds <a class="header-anchor" href="#declare-kinds" aria-label="Permalink to &quot;Declare kinds&quot;">​</a></h2><p>Author <code>agent/artifacts.ts</code> with <code>defineArtifacts</code> from <code>@cursor/july/artifacts</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;"> { 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>
1
+ import{_ as a,c as e,o as i,ag as t}from"./chunks/framework.BCISBCiQ.js";const k=JSON.parse('{"title":"Artifacts","description":"Tag durable outputs (reviewed PRs, reports) so they persist across sessions, stream as events, and list over HTTP.","frontmatter":{"title":"Artifacts","description":"Tag durable outputs (reviewed PRs, reports) so they persist across sessions, stream as events, and list over HTTP."},"headers":[],"relativePath":"reference/artifacts.md","filePath":"reference/artifacts.md"}'),n={name:"reference/artifacts.md"};function d(o,s,r,l,h,p){return i(),e("div",null,[...s[0]||(s[0]=[t(`<h1 id="artifacts" tabindex="-1">Artifacts <a class="header-anchor" href="#artifacts" aria-label="Permalink to &quot;Artifacts&quot;">​</a></h1><p>An artifact marks a durable output the agent produced: a reviewed PR URL, a generated report, a decision record. Sessions come and go; artifacts persist across them, capped and listable, so the people supervising an agent see what it shipped without replaying event streams.</p><h2 id="declare-kinds" tabindex="-1">Declare kinds <a class="header-anchor" href="#declare-kinds" aria-label="Permalink to &quot;Declare kinds&quot;">​</a></h2><p>Author <code>agent/artifacts.ts</code> with <code>defineArtifacts</code> from <code>@cursor/july/artifacts</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;"> { 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>
2
2
  <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { defineArtifacts } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &quot;@cursor/july/artifacts&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
3
3
  <span class="line"></span>
4
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;"> defineArtifacts</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
@@ -1 +1 @@
1
- import{_ as a,c as e,o as i,ag as t}from"./chunks/framework.CAZyNGu9.js";const k=JSON.parse('{"title":"Artifacts","description":"Tag durable outputs (reviewed PRs, reports) so they persist across sessions, stream as events, and list over HTTP.","frontmatter":{"title":"Artifacts","description":"Tag durable outputs (reviewed PRs, reports) so they persist across sessions, stream as events, and list over HTTP."},"headers":[],"relativePath":"reference/artifacts.md","filePath":"reference/artifacts.md"}'),n={name:"reference/artifacts.md"};function d(o,s,r,l,h,p){return i(),e("div",null,[...s[0]||(s[0]=[t("",23)])])}const g=a(n,[["render",d]]);export{k as __pageData,g as default};
1
+ import{_ as a,c as e,o as i,ag as t}from"./chunks/framework.BCISBCiQ.js";const k=JSON.parse('{"title":"Artifacts","description":"Tag durable outputs (reviewed PRs, reports) so they persist across sessions, stream as events, and list over HTTP.","frontmatter":{"title":"Artifacts","description":"Tag durable outputs (reviewed PRs, reports) so they persist across sessions, stream as events, and list over HTTP."},"headers":[],"relativePath":"reference/artifacts.md","filePath":"reference/artifacts.md"}'),n={name:"reference/artifacts.md"};function d(o,s,r,l,h,p){return i(),e("div",null,[...s[0]||(s[0]=[t("",23)])])}const g=a(n,[["render",d]]);export{k as __pageData,g as default};
@@ -1,4 +1,4 @@
1
- import{_ as e,c as a,o as i,ag as t}from"./chunks/framework.CAZyNGu9.js";const k=JSON.parse('{"title":"Channels","description":"The authoring reference for defineChannel, the built-in HTTP channel, route schemas, handler args, and the auth policies.","frontmatter":{"title":"Channels","description":"The authoring reference for defineChannel, the built-in HTTP channel, route schemas, handler args, and the auth policies."},"headers":[],"relativePath":"reference/channels.md","filePath":"reference/channels.md"}'),n={name:"reference/channels.md"};function h(o,s,l,d,r,p){return i(),a("div",null,[...s[0]||(s[0]=[t(`<h1 id="channels" tabindex="-1">Channels <a class="header-anchor" href="#channels" aria-label="Permalink to &quot;Channels&quot;">​</a></h1><p>A channel is the surface an agent lives on. The built-in HTTP session channel is always mounted. Custom channels declare their own routes under <code>/v1/channels/&lt;id&gt;</code>. The Slack and GitHub packs are prebuilt channels with platform transports. This page is the authoring reference; for the walkthrough, see the <a href="./../guides/webhooks.html">Webhooks guide</a>.</p><h2 id="the-built-in-http-channel" tabindex="-1">The built-in HTTP channel <a class="header-anchor" href="#the-built-in-http-channel" aria-label="Permalink to &quot;The built-in HTTP channel&quot;">​</a></h2><p>It&#39;s always mounted, under <code>/&lt;slug&gt;</code> in the default multi-agent layout: session create, follow-up, stream, stop, the sessions list, approvals, deterministic tool calls, health, and info. For the route-by-route contract, see the <a href="./http-api.html">HTTP API reference</a>.</p><p>Author <code>agent/channels/http.ts</code> only to override its defaults:</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;"> {</span></span>
1
+ import{_ as e,c as a,o as i,ag as t}from"./chunks/framework.BCISBCiQ.js";const k=JSON.parse('{"title":"Channels","description":"The authoring reference for defineChannel, the built-in HTTP channel, route schemas, handler args, and the auth policies.","frontmatter":{"title":"Channels","description":"The authoring reference for defineChannel, the built-in HTTP channel, route schemas, handler args, and the auth policies."},"headers":[],"relativePath":"reference/channels.md","filePath":"reference/channels.md"}'),n={name:"reference/channels.md"};function h(o,s,l,d,r,p){return i(),a("div",null,[...s[0]||(s[0]=[t(`<h1 id="channels" tabindex="-1">Channels <a class="header-anchor" href="#channels" aria-label="Permalink to &quot;Channels&quot;">​</a></h1><p>A channel is the surface an agent lives on. The built-in HTTP session channel is always mounted. Custom channels declare their own routes under <code>/v1/channels/&lt;id&gt;</code>. The Slack and GitHub packs are prebuilt channels with platform transports. This page is the authoring reference; for the walkthrough, see the <a href="./../guides/webhooks.html">Webhooks guide</a>.</p><h2 id="the-built-in-http-channel" tabindex="-1">The built-in HTTP channel <a class="header-anchor" href="#the-built-in-http-channel" aria-label="Permalink to &quot;The built-in HTTP channel&quot;">​</a></h2><p>It&#39;s always mounted, under <code>/&lt;slug&gt;</code> in the default multi-agent layout: session create, follow-up, stream, stop, the sessions list, approvals, deterministic tool calls, health, and info. For the route-by-route contract, see the <a href="./http-api.html">HTTP API reference</a>.</p><p>Author <code>agent/channels/http.ts</code> only to override its defaults:</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;"> {</span></span>
2
2
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> bearerAuth,</span></span>
3
3
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> httpChannel,</span></span>
4
4
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> localDevStrict,</span></span>
@@ -50,4 +50,4 @@ import{_ as e,c as a,o as i,ag as t}from"./chunks/framework.CAZyNGu9.js";const k
50
50
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
51
51
  <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
52
52
  <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // auth: [...], state: {...}, onStart(...), onStop(...)</span></span>
53
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span></code></pre></div><p>This example assumes <code>agent/tools/inspect_pr.ts</code> exists. The handler calls it before the model turn, so every review starts with validated PR data. It also derives a stable conversation key from the PR URL and writes the tool result to <code>pr.json</code>. Instructions can ask the model to inspect a PR, but host code guarantees it.</p><h2 id="route-verbs-and-schemas" tabindex="-1">Route verbs and schemas <a class="header-anchor" href="#route-verbs-and-schemas" aria-label="Permalink to &quot;Route verbs and schemas&quot;">​</a></h2><p><code>GET</code>, <code>POST</code>, <code>PUT</code>, <code>PATCH</code>, and <code>DELETE</code> helpers build routes. Their schemas are Zod, enforced at compile time:</p><table tabindex="0"><thead><tr><th>Verb</th><th>Required schema</th></tr></thead><tbody><tr><td><code>GET</code></td><td><code>querySchema</code></td></tr><tr><td><code>POST</code> / <code>PUT</code> / <code>PATCH</code></td><td><code>bodySchema</code> (optional <code>querySchema</code>)</td></tr><tr><td><code>DELETE</code></td><td>both optional</td></tr></tbody></table><p>Plain JSON Schema objects won&#39;t type-check; use <code>z.object({})</code> or <code>z.unknown()</code> for intentionally open surfaces. The host validates before the handler runs. Handlers receive typed <code>args.body</code> and <code>args.query</code>, and empty POST bodies are coerced to <code>{}</code> first. Declared schemas are projected on <code>GET /v1/info</code>, which powers the playground&#39;s <strong>Try</strong> buttons and composer <strong>slash commands</strong>.</p><h2 id="handler-arguments" tabindex="-1">Handler arguments <a class="header-anchor" href="#handler-arguments" aria-label="Permalink to &quot;Handler arguments&quot;">​</a></h2><p>Handlers receive the Fetch <code>Request</code> and an args object:</p><table tabindex="0"><thead><tr><th>Member</th><th>What it is</th></tr></thead><tbody><tr><td><code>send(message, options?)</code></td><td>Run a model turn on this channel; returns the session handle (options below)</td></tr><tr><td><code>getSession(sessionId)</code></td><td>Look up an existing session on this channel</td></tr><tr><td><code>receive(channelDefinition, input)</code></td><td>Hand off to another channel (schedules use this)</td></tr><tr><td><code>callTool(name, input, options?)</code></td><td>Deterministic server-tool call (<a href="./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 <code>:param</code> path segments</td></tr><tr><td><code>auth</code></td><td>The <code>AuthContext</code> resolved by this route&#39;s auth chain</td></tr><tr><td><code>requestIp</code></td><td>The TCP peer address</td></tr><tr><td><code>host</code></td><td>Shared services: <code>host.mcp</code>, <code>host.github</code>, <code>host.slack</code>, <code>host.kv</code>, <code>host.files</code>, <code>host.reminders</code></td></tr><tr><td><code>waitUntil(promise)</code></td><td>Background work that outlives the response</td></tr><tr><td><code>sessionUrls(request, sessionId)</code></td><td>Absolute playground + trace URLs for a session on this mount</td></tr><tr><td><code>artifacts</code></td><td>Unbound <a href="./artifacts.html">artifacts</a> facade; pass <code>sessionId</code> in <code>tag</code> input to attribute one</td></tr></tbody></table><p><code>send</code> options: <code>continuationToken</code> (the conversation key), <code>admission</code> (<code>&quot;preempt&quot;</code> interrupts a busy session, the default; <code>&quot;coalesce&quot;</code> enqueues behind the running turn, the <a href="./sessions.html#what-happens-when-i-send-a-follow-up">Slack policy</a>), <code>workspaceFiles</code>, <code>workspaceDir</code>, <code>cloud</code> (attach cloud repos for this session), <code>auth</code> (defaults to the request principal), <code>sdkAgentId</code> (resume a specific SDK agent), <code>state</code> (starting channel state for new sessions), <code>title</code> (session display title), <code>purpose</code> (<code>&quot;eval&quot;</code> skips sticky A/B enrollment), and <code>coalesceSourceTs</code> (dedupe key for coalesce queue items already delivered mid-turn).</p><h2 id="events" tabindex="-1">Events <a class="header-anchor" href="#events" aria-label="Permalink to &quot;Events&quot;">​</a></h2><p>The <code>events</code> map subscribes the channel to stream events for the sessions it owns. Keys are event types from the <a href="./sessions.html#which-events-can-i-stream">event vocabulary</a>, or <code>&quot;*&quot;</code>. Handlers receive <code>(event, channel, ctx)</code>, where <code>channel.state</code> is the per-session adapter state and <code>ctx</code> exposes session info and host services. This is where a channel delivers replies back to its surface.</p><h2 id="state-and-lifecycle" tabindex="-1">State and lifecycle <a class="header-anchor" href="#state-and-lifecycle" aria-label="Permalink to &quot;State and lifecycle&quot;">​</a></h2><p><code>state</code> declares the starting per-session adapter state (JSON), persisted on the session record. Routes and event handlers read and mutate it through <code>channel.state</code>. <code>onStart(args)</code> runs when the channel mounts; the Slack pack opens its Socket Mode connection here. <code>onStop()</code> runs when the server drains.</p><p><code>onStart</code> receives the route helpers (<code>send</code>, <code>getSession</code>, <code>receive</code>, <code>callTool</code>, <code>host</code>, <code>waitUntil</code>, <code>artifacts</code>, and a <code>logger</code> that respects the server&#39;s log sink) plus a set that exists for long-lived transports:</p><ul><li><code>emitAssistantMessage(sessionId, text)</code> appends an assistant message without a model turn, for host tasks that already produced the final text.</li><li><code>hasContinuationSession(token)</code> and <code>isContinuationBusy(token)</code> report whether a continuation token has a live session and whether a turn is in flight on it.</li><li><code>getContinuationLastBotMessageTs(token)</code> reads the Slack warm-delta watermark from channel state.</li><li><code>interruptContinuation(token)</code> stops the in-flight turn and clears coalesced follow-ups queued behind it.</li><li><code>resolveApproval(sessionId, callId, decision, auth, options?)</code> approves or denies a parked tool call, how Slack Block Kit buttons unblock a turn without the HTTP approvals route.</li></ul><h2 id="auth-policies" tabindex="-1">Auth policies <a class="header-anchor" href="#auth-policies" aria-label="Permalink to &quot;Auth policies&quot;">​</a></h2><p>Every route runs an auth-policy chain: the channel&#39;s <code>auth</code> array, or <code>[localDevStrict()]</code> when unset. A policy is a function <code>(request, info) =&gt; AuthContext | null</code> (async allowed); the first non-null wins, and a request no policy admits gets <code>401</code>.</p><table tabindex="0"><thead><tr><th>Policy</th><th>Admits</th></tr></thead><tbody><tr><td><code>localDevStrict()</code></td><td>Direct loopback callers with no proxy-forwarding headers (<code>X-Forwarded-For</code>, <code>X-Real-IP</code>, <code>Forwarded</code>, and <code>X-Forwarded-Host</code> are all rejected, so tunnels and same-host reverse proxies don&#39;t silently re-expose the route), plus a loopback <code>Host</code> header, which rejects DNS-rebinding callers that reach 127.0.0.1 with a remote hostname.</td></tr><tr><td><code>localDev()</code></td><td>Like <code>localDevStrict()</code> but without the <code>Host</code> check. An explicit, weaker opt-in.</td></tr><tr><td><code>loopbackOnly()</code></td><td>A loopback TCP peer, ignoring forwarding headers; for dev relays that legitimately carry them, like <code>gh webhook forward</code>.</td></tr><tr><td><code>bearerAuth(token)</code></td><td><code>Authorization: Bearer &lt;token&gt;</code>, compared in constant time. Also accepts a verifier function mapping a presented token to an <code>AuthContext</code>.</td></tr><tr><td><code>allowAll()</code></td><td>Everyone, as an <code>anonymous</code> principal. Only for surfaces protected upstream (an HMAC-verified webhook) or intentionally public.</td></tr></tbody></table><p>The resolved <code>AuthContext</code> (<code>{ authenticator, principalId, principalType, attributes? }</code>) becomes the request principal. Sessions bind to the principal that created them, and follow-up, stream, and list routes enforce ownership (<code>403</code> otherwise).</p><p>Server flags interact with authored auth: <code>--bearer-token</code> swaps the default <code>localDevStrict()</code> for <code>bearerAuth(...)</code> on channels that don&#39;t author their own chain, and <code>--allow-anonymous</code> swaps it for <code>allowAll()</code>. Authored <code>auth</code> arrays always win over both. A channel that declares <code>[localDevStrict()]</code> stays loopback-only even on an <code>--allow-anonymous</code> host.</p><h2 id="first-class-channels" tabindex="-1">First class channels <a class="header-anchor" href="#first-class-channels" aria-label="Permalink to &quot;First class channels&quot;">​</a></h2><p><strong>Slack</strong> (<code>@cursor/july/channels/slack</code>): Socket Mode transport, streaming replies, engagement rules, approval cards, and a default block on Slack Connect / guest / other-workspace senders. Author <code>agent/channels/slack.ts</code> with <code>slackChannel()</code>. Guide: <a href="./../guides/slack.html">Slack</a>.</p><p><strong>GitHub</strong> (<code>@cursor/july/channels/github</code>): webhook dispatch with signature verification, per-event hooks returning <code>{ auth }</code> (a model turn), <code>{ task }</code> (host work), or <code>null</code>, and CLI tooling for replay and live forwarding. Author <code>agent/channels/github.ts</code> with <code>githubChannel()</code>. Opt-in <code>progress.commitStatus</code> and <code>progress.banner</code> converge a merge-box check and sticky PR comment from default stream events. Guide: <a href="./../guides/github.html">GitHub</a>.</p><p><strong>Deployments</strong> (<code>@cursor/july/channels/deployments</code>): pull transport over <code>/v0/deployment-events</code>. Subscribe per deploy source with <code>deploySourceUris</code>, narrow with <code>environments</code> / <code>events</code>, and handle each event in <code>onEvent</code>. <code>deploySourceUris</code> must match <code>Deployment.deploy_source_uri</code> as your deployment writer records it; the field has no format, and matching is case-insensitive but otherwise literal. Each event carries <code>deploySourceUri</code> and <code>deployVersion</code>. Author <code>agent/channels/deployments.ts</code> with <code>deploymentsChannel()</code>. The serve host discovers every mounted deployments channel, runs one relay for the process against the union of their deploy sources, and routes each event to the channels that asked for it; the Slack and SCM relays use the same ownership. It authenticates with the host credential and keeps a durable offset, so a restart resumes rather than dropping events. An empty <code>deploySourceUris</code> list mounts the channel but starts no relay for it, so an env-configured agent stays inert until its deploy sources are set.</p><p>For other platforms like Discord or Teams, use the authored <code>defineChannel</code> webhook form.</p><h2 id="continuation-semantics" tabindex="-1">Continuation semantics <a class="header-anchor" href="#continuation-semantics" aria-label="Permalink to &quot;Continuation semantics&quot;">​</a></h2><p>Channels own their continuation-token format. The built-in HTTP channel mints opaque rotating tokens, Slack uses <code>channelId:threadTs</code>, and PR automations use keys like <code>pr:owner/repo#N</code>. Same token, same durable session; one active continuation per session; the HTTP channel returns <code>409</code> for stale tokens. For the full session model, see <a href="./sessions.html">Sessions</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="./../guides/webhooks.html">Webhooks guide</a>: the same API, walked through</li><li><a href="./http-api.html">HTTP API</a>: the built-in routes precisely</li><li><a href="./sessions.html">Sessions and streaming</a>: the events channels subscribe to</li></ul>`,39)])])}const E=e(n,[["render",h]]);export{k as __pageData,E as default};
53
+ <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span></code></pre></div><p>This example assumes <code>agent/tools/inspect_pr.ts</code> exists. The handler calls it before the model turn, so every review starts with validated PR data. It also derives a stable conversation key from the PR URL and writes the tool result to <code>pr.json</code>. Instructions can ask the model to inspect a PR, but host code guarantees it.</p><h2 id="route-verbs-and-schemas" tabindex="-1">Route verbs and schemas <a class="header-anchor" href="#route-verbs-and-schemas" aria-label="Permalink to &quot;Route verbs and schemas&quot;">​</a></h2><p><code>GET</code>, <code>POST</code>, <code>PUT</code>, <code>PATCH</code>, and <code>DELETE</code> helpers build routes. Their schemas are Zod, enforced at compile time:</p><table tabindex="0"><thead><tr><th>Verb</th><th>Required schema</th></tr></thead><tbody><tr><td><code>GET</code></td><td><code>querySchema</code></td></tr><tr><td><code>POST</code> / <code>PUT</code> / <code>PATCH</code></td><td><code>bodySchema</code> (optional <code>querySchema</code>)</td></tr><tr><td><code>DELETE</code></td><td>both optional</td></tr></tbody></table><p>Plain JSON Schema objects won&#39;t type-check; use <code>z.object({})</code> or <code>z.unknown()</code> for intentionally open surfaces. The host validates before the handler runs. Handlers receive typed <code>args.body</code> and <code>args.query</code>, and empty POST bodies are coerced to <code>{}</code> first. Declared schemas are projected on <code>GET /v1/info</code>, which powers the playground&#39;s <strong>Try</strong> buttons and composer <strong>slash commands</strong>.</p><h2 id="handler-arguments" tabindex="-1">Handler arguments <a class="header-anchor" href="#handler-arguments" aria-label="Permalink to &quot;Handler arguments&quot;">​</a></h2><p>Handlers receive the Fetch <code>Request</code> and an args object:</p><table tabindex="0"><thead><tr><th>Member</th><th>What it is</th></tr></thead><tbody><tr><td><code>send(message, options?)</code></td><td>Run a model turn on this channel; returns the session handle (options below)</td></tr><tr><td><code>getSession(sessionId)</code></td><td>Look up an existing session on this channel</td></tr><tr><td><code>receive(channelDefinition, input)</code></td><td>Hand off to another channel (schedules use this)</td></tr><tr><td><code>callTool(name, input, options?)</code></td><td>Deterministic server-tool call (<a href="./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 <code>:param</code> path segments</td></tr><tr><td><code>auth</code></td><td>The <code>AuthContext</code> resolved by this route&#39;s auth chain</td></tr><tr><td><code>requestIp</code></td><td>The TCP peer address</td></tr><tr><td><code>host</code></td><td>Shared services: <code>host.mcp</code>, <code>host.github</code>, <code>host.slack</code>, <code>host.kv</code>, <code>host.files</code>, <code>host.reminders</code></td></tr><tr><td><code>waitUntil(promise)</code></td><td>Background work that outlives the response</td></tr><tr><td><code>sessionUrls(request, sessionId)</code></td><td>Absolute playground + trace URLs for a session on this mount</td></tr><tr><td><code>artifacts</code></td><td>Unbound <a href="./artifacts.html">artifacts</a> facade; pass <code>sessionId</code> in <code>tag</code> input to attribute one</td></tr></tbody></table><p><code>send</code> options: <code>continuationToken</code> (the conversation key), <code>admission</code> (<code>&quot;preempt&quot;</code> interrupts a busy session, the default; <code>&quot;coalesce&quot;</code> enqueues behind the running turn, the <a href="./sessions.html#what-happens-when-i-send-a-follow-up">Slack policy</a>), <code>workspaceFiles</code>, <code>workspaceDir</code>, <code>cloud</code> (attach cloud repos for this session), <code>auth</code> (defaults to the request principal), <code>sdkAgentId</code> (resume a specific SDK agent), <code>state</code> (starting channel state for new sessions), <code>title</code> (session display title), <code>purpose</code> (<code>&quot;eval&quot;</code> skips sticky A/B enrollment), and <code>coalesceSourceTs</code> (dedupe key for coalesce queue items already delivered mid-turn).</p><h2 id="events" tabindex="-1">Events <a class="header-anchor" href="#events" aria-label="Permalink to &quot;Events&quot;">​</a></h2><p>The <code>events</code> map subscribes the channel to stream events for the sessions it owns. Keys are event types from the <a href="./sessions.html#which-events-can-i-stream">event vocabulary</a>, or <code>&quot;*&quot;</code>. Handlers receive <code>(event, channel, ctx)</code>, where <code>channel.state</code> is the per-session adapter state and <code>ctx</code> exposes session info and host services. This is where a channel delivers replies back to its surface.</p><h2 id="state-and-lifecycle" tabindex="-1">State and lifecycle <a class="header-anchor" href="#state-and-lifecycle" aria-label="Permalink to &quot;State and lifecycle&quot;">​</a></h2><p><code>state</code> declares the starting per-session adapter state (JSON), persisted on the session record. Routes and event handlers read and mutate it through <code>channel.state</code>. <code>onStart(args)</code> runs when the channel mounts; the Slack pack opens its Socket Mode connection here. <code>onStop()</code> runs when the server drains.</p><p><code>onStart</code> receives the route helpers (<code>send</code>, <code>getSession</code>, <code>receive</code>, <code>callTool</code>, <code>host</code>, <code>waitUntil</code>, <code>artifacts</code>, and a <code>logger</code> that respects the server&#39;s log sink) plus a set that exists for long-lived transports:</p><ul><li><code>emitAssistantMessage(sessionId, text)</code> appends an assistant message without a model turn, for host tasks that already produced the final text.</li><li><code>hasContinuationSession(token)</code> and <code>isContinuationBusy(token)</code> report whether a continuation token has a live session and whether a turn is in flight on it.</li><li><code>getContinuationLastBotMessageTs(token)</code> reads the Slack warm-delta watermark from channel state.</li><li><code>interruptContinuation(token)</code> stops the in-flight turn and clears coalesced follow-ups queued behind it.</li><li><code>resolveApproval(sessionId, callId, decision, auth, options?)</code> approves or denies a parked tool call, how Slack Block Kit buttons unblock a turn without the HTTP approvals route.</li></ul><h2 id="auth-policies" tabindex="-1">Auth policies <a class="header-anchor" href="#auth-policies" aria-label="Permalink to &quot;Auth policies&quot;">​</a></h2><p>Every route runs an auth-policy chain: the channel&#39;s <code>auth</code> array, or <code>[localDevStrict()]</code> when unset. A policy is a function <code>(request, info) =&gt; AuthContext | null</code> (async allowed); the first non-null wins, and a request no policy admits gets <code>401</code>.</p><table tabindex="0"><thead><tr><th>Policy</th><th>Admits</th></tr></thead><tbody><tr><td><code>localDevStrict()</code></td><td>Direct loopback callers with no proxy-forwarding headers (<code>X-Forwarded-For</code>, <code>X-Real-IP</code>, <code>Forwarded</code>, and <code>X-Forwarded-Host</code> are all rejected, so tunnels and same-host reverse proxies don&#39;t silently re-expose the route), plus a loopback <code>Host</code> header, which rejects DNS-rebinding callers that reach 127.0.0.1 with a remote hostname.</td></tr><tr><td><code>localDev()</code></td><td>Like <code>localDevStrict()</code> but without the <code>Host</code> check. An explicit, weaker opt-in.</td></tr><tr><td><code>loopbackOnly()</code></td><td>A loopback TCP peer, ignoring forwarding headers; for dev relays that legitimately carry them, like <code>gh webhook forward</code>.</td></tr><tr><td><code>bearerAuth(token)</code></td><td><code>Authorization: Bearer &lt;token&gt;</code>, compared in constant time. Also accepts a verifier function mapping a presented token to an <code>AuthContext</code>.</td></tr><tr><td><code>allowAll()</code></td><td>Everyone, as an <code>anonymous</code> principal. Only for surfaces protected upstream (an HMAC-verified webhook) or intentionally public.</td></tr><tr><td><code>publicEndpoint()</code></td><td>Everyone on this custom channel. Managed hosting also serves the channel without an alias token. Use it only when the handler verifies the provider signature.</td></tr></tbody></table><p><code>publicEndpoint()</code> applies only to custom channel routes. It does not open the built-in session or tool API.</p><p>The resolved <code>AuthContext</code> (<code>{ authenticator, principalId, principalType, attributes? }</code>) becomes the request principal. Sessions bind to the principal that created them, and follow-up, stream, and list routes enforce ownership (<code>403</code> otherwise).</p><p>Server flags interact with authored auth: <code>--bearer-token</code> swaps the default <code>localDevStrict()</code> for <code>bearerAuth(...)</code> on channels that don&#39;t author their own chain, and <code>--allow-anonymous</code> swaps it for <code>allowAll()</code>. Authored <code>auth</code> arrays always win over both. A channel that declares <code>[localDevStrict()]</code> stays loopback-only even on an <code>--allow-anonymous</code> host.</p><h2 id="first-class-channels" tabindex="-1">First class channels <a class="header-anchor" href="#first-class-channels" aria-label="Permalink to &quot;First class channels&quot;">​</a></h2><p><strong>Slack</strong> (<code>@cursor/july/channels/slack</code>): Socket Mode transport, streaming replies, engagement rules, approval cards, and a default block on Slack Connect / guest / other-workspace senders. Author <code>agent/channels/slack.ts</code> with <code>slackChannel()</code>. Guide: <a href="./../guides/slack.html">Slack</a>.</p><p><strong>GitHub</strong> (<code>@cursor/july/channels/github</code>): webhook dispatch with signature verification, per-event hooks returning <code>{ auth }</code> (a model turn), <code>{ task }</code> (host work), or <code>null</code>, and CLI tooling for replay and live forwarding. Author <code>agent/channels/github.ts</code> with <code>githubChannel()</code>. Opt-in <code>progress.commitStatus</code> and <code>progress.banner</code> converge a merge-box check and sticky PR comment from default stream events. Guide: <a href="./../guides/github.html">GitHub</a>.</p><p><strong>Deployments</strong> (<code>@cursor/july/channels/deployments</code>): pull transport over <code>/v0/deployment-events</code>. Subscribe per deploy source with <code>deploySourceUris</code>, narrow with <code>environments</code> / <code>events</code>, and handle each event in <code>onEvent</code>. <code>deploySourceUris</code> must match <code>Deployment.deploy_source_uri</code> as your deployment writer records it; the field has no format, and matching is case-insensitive but otherwise literal. Each event carries <code>deploySourceUri</code> and <code>deployVersion</code>. Author <code>agent/channels/deployments.ts</code> with <code>deploymentsChannel()</code>. The serve host discovers every mounted deployments channel, runs one relay for the process against the union of their deploy sources, and routes each event to the channels that asked for it; the Slack and SCM relays use the same ownership. It authenticates with the host credential and keeps a durable offset, so a restart resumes rather than dropping events. An empty <code>deploySourceUris</code> list mounts the channel but starts no relay for it, so an env-configured agent stays inert until its deploy sources are set.</p><p>For other platforms like Discord or Teams, use the authored <code>defineChannel</code> webhook form.</p><h2 id="continuation-semantics" tabindex="-1">Continuation semantics <a class="header-anchor" href="#continuation-semantics" aria-label="Permalink to &quot;Continuation semantics&quot;">​</a></h2><p>Channels own their continuation-token format. The built-in HTTP channel mints opaque rotating tokens, Slack uses <code>channelId:threadTs</code>, and PR automations use keys like <code>pr:owner/repo#N</code>. Same token, same durable session; one active continuation per session; the HTTP channel returns <code>409</code> for stale tokens. For the full session model, see <a href="./sessions.html">Sessions</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="./../guides/webhooks.html">Webhooks guide</a>: the same API, walked through</li><li><a href="./http-api.html">HTTP API</a>: the built-in routes precisely</li><li><a href="./sessions.html">Sessions and streaming</a>: the events channels subscribe to</li></ul>`,40)])])}const E=e(n,[["render",h]]);export{k as __pageData,E as default};
@@ -1 +1 @@
1
- import{_ as e,c as a,o as i,ag as t}from"./chunks/framework.CAZyNGu9.js";const k=JSON.parse('{"title":"Channels","description":"The authoring reference for defineChannel, the built-in HTTP channel, route schemas, handler args, and the auth policies.","frontmatter":{"title":"Channels","description":"The authoring reference for defineChannel, the built-in HTTP channel, route schemas, handler args, and the auth policies."},"headers":[],"relativePath":"reference/channels.md","filePath":"reference/channels.md"}'),n={name:"reference/channels.md"};function h(o,s,l,d,r,p){return i(),a("div",null,[...s[0]||(s[0]=[t("",39)])])}const E=e(n,[["render",h]]);export{k as __pageData,E as default};
1
+ import{_ as e,c as a,o as i,ag as t}from"./chunks/framework.BCISBCiQ.js";const k=JSON.parse('{"title":"Channels","description":"The authoring reference for defineChannel, the built-in HTTP channel, route schemas, handler args, and the auth policies.","frontmatter":{"title":"Channels","description":"The authoring reference for defineChannel, the built-in HTTP channel, route schemas, handler args, and the auth policies."},"headers":[],"relativePath":"reference/channels.md","filePath":"reference/channels.md"}'),n={name:"reference/channels.md"};function h(o,s,l,d,r,p){return i(),a("div",null,[...s[0]||(s[0]=[t("",40)])])}const E=e(n,[["render",h]]);export{k as __pageData,E as default};